【AT2568】Lotus Leaves

題意

鏈接:AT2568

一個池塘,有起點葉子、終點葉子和葉子。
同行同列的葉子聯通,問最少刪去多少葉子(除起點終點)能使得起點和終點不連通。

解法:網絡流

題目顯然要求圖的最小割。(暴力建邊帶走)

更優解?

將每行、每列各縮爲一點,然後對於一片葉子(i,j) ,從行i 向列j 連雙向邊,從超源向它所在的行與列連單向邊,從超匯所在行與列向其連單向邊,完成建模。(注意無解的特判)

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>

#define EXIT {puts("-1");return 0;}

using namespace std;

struct edge{
    int v,c;
    edge():v(0),c(0){}
    edge(int w,int d):v(w),c(d){}
};

vector<edge> vec;
vector<int> point[301];
int d[301],n,m,S,T;
char s[202][202];
queue<int> q;

inline void addedge(int x,int y,int c){point[x].push_back(vec.size()),vec.push_back(edge(y,c));point[y].push_back(vec.size()),vec.push_back(edge(x,0));}

bool bfs(){
    memset(d,0,sizeof(d));
    q.push(S);
    d[S]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i:point[u]){
            edge e=vec[i];int v=e.v,c=e.c;
            if(!d[v]&&c)d[v]=d[u]+1,q.push(v);
        }
    }
    return d[T];
}

int dfs(int u,int flow){
    if(u==T)return flow;
    for(int i:point[u]){
        edge e=vec[i];int v=e.v,c=e.c,fl;
        if(d[v]==d[u]+1&&c&&(fl=dfs(v,min(c,flow)))){vec[i].c-=fl,vec[i^1].c+=fl;return fl;}
    }
    return 0;
}

int main(){
    scanf("%d%d",&n,&m);
    T=(S=n+m+1)+1;
    for(int i=1;i<=n;++i){
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;++j){
            if(s[i][j]=='o')addedge(i+m,j,1),addedge(j,i+m,1);
            if(s[i][j]=='S')addedge(S,i+m,2147483647),addedge(S,j,2147483647);
            if(s[i][j]=='T')addedge(i+m,T,2147483647),addedge(j,T,2147483647);
        }
    }
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(s[i][j]=='S'){for(int k=1;k<=n;++k)if(s[k][j]=='T')EXIT;for(int k=1;k<=m;++k)if(s[i][k]=='T')EXIT;}
    int ans=0;
    while(bfs()){int flow;while(flow=dfs(S,2147483647))ans+=flow;}
    printf("%d",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章