首页 > 代码库 > [hdu 4307]Matrix

[hdu 4307]Matrix

真是一道很好的题目喵~

一看题面真是无语了……很直接、很暴力、很恶心。说实话,除了 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         else122         {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 }
本傻装B系列

 

这道题告诉我们,如果要求的是一个最大/小化某个表达式的数组,且每个数字的取值范围都很小时可以考虑用最小割做~

 

[hdu 4307]Matrix