1 做得还算麻利~ 2 /*最大闭合子图 3 题意:建通讯站。每个通讯站有一定耗费,两个特定的通讯站之间建立通讯以后 4 会有一定收益,问怎样建立通讯站可以使得收益最大 。 5 ——最大权闭合子图->最小割 6 ——url:http://acm.hdu.edu.cn/showproblem.php?pid=3879 7 思路: 8 首先考虑将图转化。 9 即一条通讯线路有一定收益wi(即为正点权),但需要建立两个通讯站, 10 这两个通讯站有一定造价pi(即为负点权)。 11 将通讯线路也变成点,点权为收益,连两条有向只向两个通讯站。 12 原来的通讯站点权不变。则start=0;end=m+n+1;totals=end+1; 13 由此,题目转化为在新的图中求一个闭合图,使得其点权最大,即最大权闭合子图 14 具体见图如下: 15 建一个源点Start,与每个通讯线路的点相连,边权为收益 16 建一个汇点end,end与每个通讯站相连,边权为建造费用 17 通讯站与通讯线路之间的边权为无穷大 18 最后的结果为所有通讯线路总的收益-最小割(最大流) 19 */ 20 #include21 #include 22 #include 23 #include 24 #include 25 #include 26 using namespace std; 27 #define min(a,b) ((a)<(b))?(a):(b) 28 #define max(a,b) ((a)>(b))?(a):(b) 29 #define MAXN 60000//这里取略大于m+n+2的值(500+50000+2)所以这里取60000否则会runtime error 30 #define MAXM 5400000//M取N的平方倍或者N*9 31 #define INF 0x3f3f3f3f 32 33 struct node 34 { 35 int n;//点编号 36 int w;//点权 37 }Node[MAXN]; 38 //链式前向星 39 struct enode 40 { 41 int t; 42 int w; //权值 43 int c; //流量 44 // int cost; 45 // int pre; //前向指针 46 int next; 47 }; 48 49 50 struct enode e[MAXM]; 51 int box[MAXN],ecnt; 52 //int etail[MAXN]; //尾部 53 void init() 54 { 55 ecnt=0; 56 memset(box,-1,sizeof(box)); 57 // memset(etail,-1,sizeof(etail)); //初始化尾部 58 } 59 void addedge(int f,int t,int c) //流量重载 60 { 61 e[ecnt].next=box[f]; 62 e[ecnt].t=t; 63 e[ecnt].c=c; 64 box[f]=ecnt++; 65 e[ecnt].next=box[t]; 66 e[ecnt].t=f; 67 e[ecnt].c=0; 68 box[t]=ecnt++; 69 } 70 int sap(int s,int t,int N)//最大流问题 71 { 72 int gap[MAXN],lvl[MAXN],cur[MAXN],pre[MAXN]; 73 int curflow,ans=0,u,tmp,neck,i; 74 memset(lvl,0,sizeof(lvl)); 75 memset(gap,0,sizeof(gap)); 76 memset(pre,-1,sizeof(pre)); 77 for(i=0;i ) 78 cur[i]=box[i]; 79 gap[0]=N; 80 u=s; 81 while(lvl[s]<N) 82 { 83 if(u==t) 84 { 85 curflow=INF; 86 for(i=s;i!=t;i=e[cur[i]].t) 87 { 88 if(curflow>e[cur[i]].c) 89 { 90 neck=i; 91 curflow=e[cur[i]].c; 92 } 93 } 94 for(i=s;i!=t;i=e[cur[i]].t) 95 { 96 tmp=cur[i]; 97 e[tmp].c-=curflow; 98 e[tmp^1].c+=curflow; 99 } 100 ans+=curflow; 101 u=neck; 102 } 103 for(i=cur[u];i!=-1;i=e[i].next) 104 if(e[i].c && lvl[u]==lvl[e[i].t]+1) 105 break; 106 if(i!=-1) 107 { 108 cur[u]=i; 109 pre[e[i].t]=u; 110 u=e[i].t; 111 } 112 else 113 { 114 if(--gap[lvl[u]]==0) 115 break; 116 cur[u]=box[u]; 117 for(tmp=N,i=box[u];i!=-1;i=e[i].next) 118 if(e[i].c) 119 tmp=min(tmp,lvl[e[i].t]); 120 lvl[u]=tmp+1; 121 gap[lvl[u]]++; 122 if(u!=s) 123 u=pre[u]; 124 } 125 } 126 return ans; 127 } 128 int main() 129 { 130 int m,n,a,b,c,t,w; 131 int i,j,k; 132 int start,end,ans; 133 while(scanf("%d%d",&n,&m)!=EOF) //; 134 { 135 //scanf("%d%d",&n,&m); 136 start=ans=0; 137 end=n+m+1; 138 init(); 139 for(i=1;i<=n;i++) 140 { 141 scanf("%d",&w); 142 addedge(i+m,end,w);//终点和负点权边相连 143 144 } 145 for(i=1;i<=m;i++) 146 { 147 scanf("%d%d%d",&a,&b,&c);//正点权 148 ans+=c; 149 addedge(i,b+m,INF);//建图关键 150 addedge(i,a+m,INF);//建图关键 151 addedge(start,i,c); 152 } 153 t=sap( start,end,end+1);//*/ 154 printf("%d\n",ans-t); 155 } 156 return 0; 157 } 158 /* 159 Sample Input 160 161 5 5 162 1 2 3 4 5 163 1 2 3 164 2 3 4 165 1 3 3 166 1 4 2 167 4 5 3 168 169 Sample Output 170 171 2 172 */