标签:style blog http color io os ar for 数据
真是一道很好的题目喵~
一看题面真是无语了……很直接、很暴力、很恶心。说实话,除了 straight forward 我脑子里就没想过别的
上网看了一下居然是最小割,脑子里面一下子就清醒了,N<=1000 而且 A[i]=0 or 1 的,似乎数据上具备了网络流的前提~
现在来看一看那个公式:
稍微变一变:
这样就非常明显了,要最大化 D 的值,就要最小化后面括号里的表达式
而表达式的值仅和 ai 的值有关,可以视为:
若取 ai=0 时,要付出 ∑bij 的代价,若取 ai=1,则要付出 ci 的代价,同时,若 ai=1 且 aj=0 ,则又要付出 bij 的代价,问最小代价
这尼玛经典的最小割,建立源点 S 汇点 T ,令 ai 向 S 和 T 连边,若 ai 最终与 S 相连则 ai=1,否则 ai=0,再在 ai 和 aj 间连一条边,表示若 ai 和 aj 最后分属不同集合,则需付出 bij 的代价
然后,这道题就被 AC 了……
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #define min(x, y) ((x)<(y) ? (x):(y)) 5 const int inf=0x7FFFFFFF; 6 const int sizeOfPoint=1024; 7 const int sizeOfEdge=33554432; 8 9 int cases; 10 int N; 11 int S, T; 12 int B[sizeOfPoint][sizeOfPoint], Bi[sizeOfPoint], C[sizeOfPoint]; 13 int h[sizeOfPoint]; 14 inline int getint(); 15 inline void putint(int); 16 17 struct edge {int point, flow; edge * next, * pair;}; 18 edge memory[sizeOfEdge], * port=memory; 19 edge * e[sizeOfPoint]; 20 inline void clear() {port=memory; memset(e, 0, sizeof e);} 21 inline edge * newedge(int point, int flow, edge * next) 22 { 23 edge * ret=port++; 24 ret->point=point; ret->flow=flow; ret->next=next; 25 return ret; 26 } 27 inline void link(int u, int v, int f) 28 { 29 e[u]=newedge(v, f, e[u]); e[v]=newedge(u, 0, e[v]); 30 e[u]->pair=e[v]; e[v]->pair=e[u]; 31 } 32 inline bool bfs(); 33 inline int aug(); 34 inline int dinic(); 35 36 int main() 37 { 38 int ans; 39 40 for (cases=getint();cases;cases--) 41 { 42 clear(); 43 N=getint(); 44 memset(Bi, 0, sizeof Bi); 45 for (int i=1;i<=N;i++) 46 for (int j=1;j<=N;j++) 47 Bi[i]+=(B[i][j]=getint()); 48 for (int i=1;i<=N;i++) 49 C[i]=getint(); 50 ans=0; 51 for (int i=1;i<=N;i++) ans+=Bi[i]; 52 53 S=0; T=N+1; 54 for (int i=1;i<=N;i++) 55 link(S, i, Bi[i]), 56 link(i, T, C[i]); 57 for (int i=1;i<=N;i++) 58 for (int j=1;j<=N;j++) if (i!=j) 59 link(i, j, B[i][j]); 60 ans-=dinic(); 61 putint(ans); 62 } 63 64 return 0; 65 } 66 inline int getint() 67 { 68 register int num=0; 69 register char ch; 70 do ch=getchar(); while (ch<‘0‘ || ch>‘9‘); 71 do num=num*10+ch-‘0‘, ch=getchar(); while (ch>=‘0‘ && ch<=‘9‘); 72 return num; 73 } 74 inline void putint(int num) 75 { 76 char stack[15]; 77 register int top=0; 78 if (num==0) stack[top=1]=‘0‘; 79 for ( ;num;num/=10) stack[++top]=num%10+‘0‘; 80 for ( ;top;top--) putchar(stack[top]); 81 putchar(‘\n‘); 82 } 83 inline bool bfs() 84 { 85 static int q[sizeOfPoint]; 86 int l=0, r=0; 87 memset(h, 0xFF, sizeof h); h[T]=0; 88 for (q[r++]=T;l<r;l++) 89 { 90 int u=q[l]; 91 for (edge * i=e[u];i;i=i->next) if (i->pair->flow && h[i->point]==-1) 92 h[q[r++]=i->point]=h[u]+1; 93 } 94 return h[S]>=0; 95 } 96 inline int aug() 97 { 98 static edge * t[sizeOfPoint], * path[sizeOfPoint]; 99 static int aug[sizeOfPoint]; 100 int flow=0; 101 memset(aug, 0, sizeof aug); aug[S]=inf; 102 memset(path, 0, sizeof path); 103 memmove(t, e, sizeof e); 104 for (int u=S; ; ) 105 { 106 if (u==T) 107 { 108 flow+=aug[T]; 109 for (edge * i=path[T];i;i=path[i->point]) 110 i->pair->flow-=aug[T], i->flow+=aug[T], aug[i->point]-=aug[T]; 111 for (edge * i=path[T];i && u==T;i=path[i->point]) if (aug[i->point]) 112 u=i->point; 113 } 114 edge *& i=t[u]; 115 for ( ;i && (!i->flow || h[i->point]+1!=h[u]);i=i->next); 116 if (i) 117 { 118 path[i->point]=i->pair; aug[i->point]=min(aug[u], i->flow); 119 u=i->point; 120 } 121 else 122 { 123 if (u==S) break; 124 h[u]=-1; 125 u=path[u]->point; 126 } 127 } 128 return flow; 129 } 130 inline int dinic() 131 { 132 register int flow=0; 133 for ( ;bfs();flow+=aug()); 134 return flow; 135 }
这道题告诉我们,如果要求的是一个最大/小化某个表达式的数组,且每个数字的取值范围都很小时可以考虑用最小割做~
标签:style blog http color io os ar for 数据
原文地址:http://www.cnblogs.com/dyllalala/p/3991656.html