标签:
题意:
给n个城市,m条有向边,每条边有权值,现在有些城市可以选择得到,可选的城市有一个价值,但是要满足从1到达不了这些城市,为了满足要求可以去掉一些边,需要花费边的权值,问最终得到的最大价值是多少,并给出方案。
最小割 = 最大流
建图很简单,源点就是1,设置汇点T。按图中的有向边关系连边。对于所有的可选择的城市u,连一条u->T的容量为w的边。跑一遍最大流,即为最小割。ans = sum - 最小割。
写出方案,就是走一遍bfs,看 哪些满流边(并且边的汇不是T,这是因为这样的边是所选的城市扩展的边),打出来就好。
代码:
#include<iostream> #include<cstdio> #include<vector> #include<queue> #include<cmath> #include<cstring> using namespace std; const int N = 1000 + 10 ; const int inf = 1000000000; typedef long long ll; struct Edge { int from,to,cap,flow; }; int n,m,s,t,num,f; int w[N],use[N]; int vis[2*N],cur[2*N]; vector<int> G[2*N]; vector<Edge> edges; queue<int> cut; void init() { edges.clear(); for(int i=1;i<=n;i++) G[i].clear(); memset(vis,0,sizeof(vis)); } int add(int u,int v,int c) { edges.push_back((Edge){u,v,c,0}); edges.push_back((Edge){v,u,0,0}); num = edges.size(); G[u].push_back(num-2); G[v].push_back(num-1); } int bfs() { int front; memset(vis,0,sizeof(vis)); vis[s] = 1; queue<int> q; q.push(s); while(!q.empty()){ front = q.front(); q.pop(); for(int i=0;i<G[front].size();i++) { Edge& e = edges[G[front][i]]; if(!vis[e.to] && e.cap > e.flow) { q.push(e.to); vis[e.to] = vis[front]+1; } } } return vis[t]; } int dfs(int x,int a) { if(x==t || a==0) return a; int f=0,flow=0; for(int i=0;i<G[x].size();i++){ Edge& e = edges[G[x][i]]; if(vis[e.to]==vis[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow)))>0 ) { flow += f; e.flow += f; a -= f; edges[G[x][i]^1].flow -= f; if(a==0) break; } } return flow; } int dinic() { int flow = 0; while(bfs()) { memset(cur,0,sizeof(cur)); flow += dfs(s,inf); } return flow; } void find_cut() { while(!cut.empty()) cut.pop(); memset(vis,0,sizeof(vis)); vis[1] = 1; queue<int> q; q.push(1); int front; while(!q.empty()){ front = q.front(); q.pop(); for(int i=0;i<G[front].size();i++){ Edge& e = edges[G[front][i]]; if(!vis[e.to] && e.cap > e.flow){ vis[e.to] = 1; q.push(e.to); } } } for(int i=1;i<=n;i++){ if(vis[i]) for(int j=0;j<G[i].size();j++){ Edge& e = edges[G[i][j]]; if(G[i][j]&1) continue; if(e.to!=t && !vis[e.to]) cut.push(G[i][j]/2+1); } } return ; } void print_cut() { int len = cut.size(); int ro; cout<<len<<" "; for(int i=1;i<len;i++){ ro = cut.front(); cut.pop(); printf("%d ",ro); } ro = cut.front(); cut.pop(); printf("%d\n",ro); } int main() { int T,cas=0; scanf("%d",&T); while(T--){ ll sum = 0; scanf("%d%d%d",&n,&m,&f); init(); s = 1; t = n+1; for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } for(int i=1;i<=f;i++){ int u,w; scanf("%d%d",&u,&w); add(u,t,w); sum += w; } ll ans = dinic(); find_cut(); printf("Case %d: %lld\n",++cas,sum-ans); print_cut(); } return 0; }
标签:
原文地址:http://blog.csdn.net/alpc_wt/article/details/44222797