ZOJ 2429 Destroying The Graph 最小割(最小点权覆盖)

来源:互联网 发布:网络借贷百度百科 编辑:程序博客网 时间:2024/06/07 08:48

点击打开链接

题意:n点,m条有向边,n<=100,m<=5000.删除i所有入边花费a[i],删除i所有出边花费b[i],问删除所有边的最小花费? 
删除边u->v代价为(a[u]或着b[v]) 则操作看成点,a[u]-b[v]连接一条边,删除所有的边相当于用点(操作)覆盖所有的边.
求二分图的最小点权覆盖即可

利用最小割模型求最小点权覆盖 
删除最小割上的边,s-t不存在路径,所以(s,u),(u,v),(v,t)至少有一条边在最小割上.
最小割上的边是满流的,人为的令(u,v)不在最小割上,则(u,v)=inf
所以(s,u),(v,t)至少一条边在最小割上 对所有边u-v,u或者v至少有一个被选中满足点权覆盖,并且最小割容量最小,所以为最小点权覆盖

#include <iostream>#include <algorithm>#include <cstring>#include <queue>#include <cstdio>#include <map>#include <vector>using namespace std;typedef long long ll;const int N=5e2+20;const int inf=2e8;int n,m,s,t,a[N],b[N];//a[i],b[i] 删除i所有入边和出边的代价int flow[N][N],dis[N],vis[N];queue<int> q; vector<int> v;int bfs(int s,int t)//建立层次图 {while(!q.empty())q.pop();memset(dis,-1,sizeof(dis));dis[s]=0,q.push(s);while(!q.empty()){int k=q.front();q.pop();for(int i=1;i<=t;i++){if(flow[k][i]>0&&dis[i]==-1)//可以到达并且未访问 {dis[i]=dis[k]+1;q.push(i);}}}if(dis[t]>=0)return 1;return 0;}int dfs(int x,int mx)//找增广路 {int f;if(x==t)return mx;int now=mx;for(int i=1;i<=t;i++){if(flow[x][i]>0&&dis[i]==dis[x]+1&&(f=dfs(i,min(mx,flow[x][i])))){flow[x][i]-=f;flow[i][x]+=f;return f;}}return 0;}void dfs(int u)//找最小割的割边 即满流边 {vis[u]=1;for(int i=0;i<=t;i++){//标记所有非满流边 if(!vis[i]&&flow[u][i])dfs(i);}}int main(){int T;cin>>T;while(T--){v.clear();memset(vis,0,sizeof(vis));memset(flow,0,sizeof(flow));cin>>n>>m;s=0,t=2*n+1;for(int i=1;i<=n;i++)scanf("%d",&a[i]),flow[i+n][t]=a[i];for(int i=1;i<=n;i++)scanf("%d",&b[i]),flow[s][i]=b[i];while(m--){int u,V;scanf("%d%d",&u,&V);flow[u][V+n]=inf;}int mx_flow=0,res;while(bfs(s,t)){while(res=dfs(s,inf))mx_flow+=res;}cout<<mx_flow<<endl;dfs(s);for(int i=1;i<=n;i++){if(!vis[i])v.push_back(i);if(vis[i+n])//说明s->u,u->i+n有流 则i+n->t肯定在最小割上  v.push_back(i+n);}cout<<v.size()<<endl;for(int i=0;i<v.size();i++){if(v[i]<=n)printf("%d-\n",v[i]);elseprintf("%d+\n",v[i]-n);}cout<<endl;}return 0;}


阅读全文
0 0