欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

洛谷P3355

程序员文章站 2022-06-08 14:26:11
...

最大流与最小割之间的转换,题目做法类似于P2774方格取数
最多放多少骑士==最少拿走多少
观察图片不难发现:黄色的不能攻击黄色的,红色同理 这一点非常重要,考虑到这一点,就可以把点分为两类,一类连源点,一类连汇点,否则的话很难建图;
那么不难想到二分图匹配
这样就转化成了二分图最小定点覆盖
而二分图最小顶点覆盖==二分图最大匹配。证明可以看这里
从S向红色连边(权重为1),从红色向能攻击到的黄色连边(权重为INF),从黄色向T连边(权重为1)
跑最大流

另一个不错的题解:
洛谷P3355

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
struct edge{
    int to,cap,rev;
};
const int N=4e4+100;
vector<edge>G[N];
int level[N],iter[N];
void addedge(int from,int to,int cap)
{
    G[from].push_back(edge{to,cap,(int)G[to].size()});
    G[to].push_back(edge{from,0,(int)G[from].size()-1});//反向容量为0!!
}
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    queue<int>que;
    level[s]=0;que.push(s);
    while(!que.empty()){
        int t=que.front();que.pop();
        for(int i=0;i<G[t].size();i++){
            edge e=G[t][i];
            if(e.cap>0&&level[e.to]<0){
                level[e.to]=level[t]+1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)
{
    if(v==t)return f;
    for(int&i=iter[v];i<G[v].size();i++){//注意传引用!
        edge&e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;//不要漏了这个,很多时候可能是无法增广的
}
int maxflow(int s,int t){
    int flow=0;
    for(;;){
        bfs(s);
        if(level[t]<0)return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while(f=dfs(s,t,0x7f7f7f7f))
            flow+=f;
    }
}
int n,m;
int get(int x,int y)
{
    return (y-1)*n+x;
}
pair<int,int> getf(int x)
{
    int i=x%n;int j=(x-i)/n+1;
    return make_pair(i,j);
}
int main()
{
    int i,j,k,a,b;
    cin>>n>>m;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++) {
            k = get(i, j);
            //addedge(0, k, 1);
            if ((i + j) & 1) {
                addedge(k, 40050, 1);
            } else {
                addedge(0, k, 1);
            }
        }
    for(i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        if((a+b)&1){
            k=get(a,b);G[k].pop_back();
        }
        else{
            k=get(a,b);j=G[k][0].rev;
            G[0][j].cap=0;
        }
    }
    int move[8][2]={2,1,1,2,2,-1,1,-2,-1,2,-2,1,-2,-1,-1,-2};
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++){
        if((i+j)&1)continue;
        for(k=0;k<8;k++){
            if(i+move[k][0]>0&&i+move[k][0]<=n&&j+move[k][1]>0&&j+move[k][1]<=n){//注意这里的i,j,k不要弄混了!!!!
                a=get(i,j);b=get(i+move[k][0],j+move[k][1]);
                addedge(a,b,1);
            }
        }
    }
    cout<<n*n-maxflow(0,40050)-m<<endl;

    return 0;
}