dyllalala

导航

[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         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 }
本傻装B系列

 

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

 

posted on 2014-09-24 22:07  dyllalala  阅读(235)  评论(0编辑  收藏  举报