这道题,水很深,线性代数当初没学好,一看见矩阵就颤抖,比赛的时候都没敢看这题,后来发布解题报告后才知道这是最小割。
建图,求maxflow,然后res-maxflow(n+1)即为所求。
用dinic居然超时了,happy457曾经告诉我dinic是永远不会出现超时现象的,它居然超时了。冷静思考一下dinic-O(V^2*E)与hlpp-O(V^2*sqrt(E))在该题上确实有差别,因为E=V*(V-1)/2,瞬间dinic复杂度变为O(V^4),而hlpp为O(V^3).我又一直没去理解hlpp,所以到网上搜了份模板,套上建图,果然1Y了。没想到的是排名倒数第一。囧。。
附AC代码:

#include <stdio.h> #include <queue> #include <string.h> using namespace std; #define V 1005 int res; queue<int> que; int ori[V][V]; int rm[V][V]; int high[V]; int e[V]; int m,n; int b[V][V]; int c[V]; void init(){ memset(high,0,sizeof(high)); memset(e,0,sizeof(e)); while(!que.empty()){ que.pop(); } high[0]=n+1; int i; for(i=0;i<=n+1;++i){ if(ori[0][i]>0){ e[0]-=ori[0][i]; e[i]+=ori[0][i]; rm[0][i]=ori[0][i]; rm[i][0]=-rm[0][i]; que.push(i); } } } int fpath(int num){ int i; int small=0x7fffffff; int spos; for(i=0;i<=n+1;++i){ if(ori[num][i]-rm[num][i]>0){ if(high[num]==high[i]+1){ return i; } if(high[i]< small){ small=high[i]; spos=i; } } } high[num]=small+1; return spos; } void push(int s,int d){ int max=ori[s][d]-rm[s][d]; if(e[s]< max){ max=e[s]; } e[s]-=max; e[d]+=max; rm[s][d]+=max; rm[d][s]=-rm[s][d]; } void deal(){ int now; int psta; while(!que.empty()){ now=que.front(); que.pop(); if(now==n+1){ continue; } while(e[now]>0){ psta=fpath(now); push(now,psta); que.push(psta); } } } void build(){ res=0; for(int i=1;i<=n;i++){ ori[0][i]+=c[i]; //addedge(0,i,c[i]); int sum=0; for(int j=1;j<=n;j++){ sum+=b[i][j]; if(i==j) continue; ori[j][i]+=b[i][j]; //addedge(j,i,b[i][j]); } ori[i][n+1]+=sum; //addedge(i,n+1,sum); res+=sum; } } int main() { //freopen("in.txt","r",stdin); int ncas; scanf("%d",&ncas); while(ncas--){ memset(ori,0,sizeof(ori)); memset(rm,0,sizeof(rm)); scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&b[i][j]); for(int i=1;i<=n;i++) scanf("%d",&c[i]); build(); init(); deal(); printf("%d\n",res-e[n+1]); } return 0; }