题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3061
由于小白同学近期习武十分刻苦,很快被晋升为天策军的统帅。而他上任的第一天,就面对了一场极其困难的战斗:
据侦查兵回报,前方共有N座城池,考虑到地势原因,最终得到一个结论:攻占某些城池之前必须攻占另外一些城池。
事实上,可以把地图看做是一张拓扑图,而攻占某个城池,就意味着必须先攻占它的所有前驱结点。
小白还做了一份调查,得到了攻占每个城池会对他的兵力产生多少消耗(当然也可能会得到增长,因为每攻占一个城池,便可以整顿军队,扩充兵力,天策军的兵力十分庞大,如果不考虑收益,他们可以攻取所有的城池)。
现在请你帮小白统帅做一份战斗计划,挑选攻打哪些城市,使得天策军在战斗过后军容最为壮大。
据侦查兵回报,前方共有N座城池,考虑到地势原因,最终得到一个结论:攻占某些城池之前必须攻占另外一些城池。
事实上,可以把地图看做是一张拓扑图,而攻占某个城池,就意味着必须先攻占它的所有前驱结点。
小白还做了一份调查,得到了攻占每个城池会对他的兵力产生多少消耗(当然也可能会得到增长,因为每攻占一个城池,便可以整顿军队,扩充兵力,天策军的兵力十分庞大,如果不考虑收益,他们可以攻取所有的城池)。
现在请你帮小白统帅做一份战斗计划,挑选攻打哪些城市,使得天策军在战斗过后军容最为壮大。
题意描述:如题所示。
算法分析:最大权闭合图的水题。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #define inf 0x7fffffff 9 using namespace std; 10 const int maxn=500+10; 11 const int M = 250000+10; 12 13 int n,m,from,to; 14 struct node 15 { 16 int v,flow; 17 int next; 18 }edge[M*3]; 19 int head[maxn],edgenum; 20 21 void add(int u,int v,int flow) 22 { 23 edge[edgenum].v=v ;edge[edgenum].flow=flow ; 24 edge[edgenum].next=head[u] ;head[u]=edgenum++ ; 25 26 edge[edgenum].v=u ;edge[edgenum].flow=0 ; 27 edge[edgenum].next=head[v] ;head[v]=edgenum++ ; 28 } 29 30 int d[maxn]; 31 int bfs() 32 { 33 memset(d,0,sizeof(d)); 34 d[from]=1; 35 queue<int> Q; 36 Q.push(from); 37 while (!Q.empty()) 38 { 39 int u=Q.front() ;Q.pop() ; 40 for (int i=head[u] ;i!=-1 ;i=edge[i].next) 41 { 42 int v=edge[i].v; 43 if (!d[v] && edge[i].flow) 44 { 45 d[v]=d[u]+1; 46 Q.push(v); 47 if (v==to) return 1; 48 } 49 } 50 } 51 return 0; 52 } 53 54 int dfs(int u,int flow) 55 { 56 if (u==to || flow==0) return flow; 57 int cap=flow; 58 for (int i=head[u] ;i!=-1 ;i=edge[i].next) 59 { 60 int v=edge[i].v; 61 if (d[v]==d[u]+1 && edge[i].flow) 62 { 63 int x=dfs(v,min(edge[i].flow,cap)); 64 edge[i].flow -= x; 65 edge[i^1].flow += x; 66 cap -= x; 67 if (cap==0) return flow; 68 } 69 } 70 return flow-cap; 71 } 72 73 int dinic() 74 { 75 int sum=0; 76 while (bfs()) sum += dfs(from,inf); 77 return sum; 78 } 79 80 int main() 81 { 82 while (scanf("%d%d",&n,&m)!=EOF) 83 { 84 int a,b; 85 memset(head,-1,sizeof(head)); 86 edgenum=0; 87 from=n+1; 88 to=from+1; 89 int sum=0; 90 for (int i=1 ;i<=n ;i++) 91 { 92 scanf("%d",&a); 93 if (a>0) {sum += a ;add(from,i,a);} 94 else add(i,to,-a); 95 } 96 for (int i=0 ;i<m ;i++) 97 { 98 scanf("%d%d",&a,&b); 99 add(a,b,inf); 100 } 101 printf("%d ",sum-dinic()); 102 } 103 return 0; 104 }