hdu 4307 Matrix(数学-最小割-最大流)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4307

 

【题意】

求一个1*N的0、1向量A,使得D = (A*B - C)*A' 最大,B,C给定元素非负,A'表示A的转置。

 

【分析】

sum(Ai * Bij * Aj) - sum(Ai * Ci)

= sum(Bij)

   - {sum((1-Ai) * Bi) + sum(Ai * Bij * (1-Aj)) + sum(Ai * Ci)}    

Bi表示第i行和,Ai = {0,1}

如此求红色部分的最小值即可。

 

观察公式可得,Ai取值0、1,套用最小割模型,加边:(s,i,Bi),(i,t,Ci),(j,i,Bij),求最小割即可。

 

dinic:531MS

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<math.h>
  4 #include<algorithm>
  5 #include<vector>
  6 #define LL long long
  7 
  8 using namespace std;
  9 
 10 const int maxn = 1011;
 11 const int maxm = 4100010;
 12 const LL inf = 999999999999;
 13 
 14 
 15 
 16 
 17 struct Dinic{
 18     int node, src, dest, ne;
 19     int head[maxn], work[maxn], dist[maxn],Q[maxn];
 20     LL flow[maxm];
 21     int pnt[maxm], nxt[maxm];
 22 
 23 
 24     void init(int _node, int _src, int _dest)
 25     {
 26         node = _node;
 27         src = _src;
 28         dest = _dest;
 29         for (int i=0;i<node;i++)
 30         {
 31             head[i] = -1;
 32         }
 33         ne = 0;
 34     }
 35     void add(int u,int v, LL c1,LL c2)
 36     {
 37         pnt[ne] = v, flow[ne] = c1, nxt[ne] = head[u], head[u] = ne++;
 38         pnt[ne] = u, flow[ne] = c2, nxt[ne] = head[v], head[v] = ne++;
 39 
 40     }
 41     bool dinic_bfs(void)
 42     {
 43         int i,u,v,l,r=0;
 44         for(int i=0;i<node;i++)    dist[i]=-1;
 45         dist[Q[r++]=src]=0;
 46         for(l=0;l<r;l++)    for(i=head[u=Q[l]];i>=0;i=nxt[i])
 47             if(flow[i] && dist[v=pnt[i]]<0)
 48             {
 49                 dist[Q[r++]=v]=dist[u]+1;
 50                 if(v==dest)    return 1;
 51             }
 52         return 0;
 53     }
 54     LL dinic_dfs(int u,LL exp)
 55     {
 56         if(u==dest)    return exp;
 57         LL tmp;
 58         for(int &i=work[u],v;i>=0;i=nxt[i])
 59             if(flow[i] && dist[v=pnt[i]]==dist[u]+1 && (tmp=dinic_dfs(v,min(exp,flow[i])))>0)
 60             {
 61                 flow[i]-=tmp;
 62                 flow[i^1]+=tmp;
 63                 return tmp;
 64             }
 65         return 0;
 66     }
 67     LL dinic_flow(void)
 68     {
 69         int i;
 70         LL res=0,delta;
 71         while(dinic_bfs())
 72         {
 73             for(i=0;i<node;i++)    work[i]=head[i];
 74             while(delta=dinic_dfs(src,inf))    res+=delta;
 75         }
 76         return res;
 77     }
 78 }Flow;
 79 
 80 int n;
 81 LL B[maxn][maxn];
 82 LL C[maxn];
 83 LL BB[maxn];
 84 int main()
 85 {
 86     int cas;
 87     scanf("%d",&cas);
 88     while  (cas--)
 89     {
 90         scanf("%d",&n);
 91         int s = 0, t = n + 1;
 92 
 93         Flow.init(n+2,s,t);
 94         LL sum = 0;
 95         for (int i=1;i<=n;i++)
 96         {
 97             BB[i] = 0;
 98             for (int j=1;j<=n;j++)
 99             {
100                 scanf("%I64d",&B[i][j]);
101                 BB[i] += B[i][j];
102                 Flow.add(i,j,B[i][j],0);
103             }
104             Flow.add(s,i,BB[i],0);
105             sum += BB[i];
106         }
107         for (int i=1;i<=n;i++)
108         {
109             scanf("%I64d",&C[i]);
110             Flow.add(i,t, C[i],0);
111         }
112 
113        // puts("dfs");
114         LL ans = sum - Flow.dinic_flow();
115 
116         printf("%I64d\n",ans);
117     }
118     return 0;
119 }
hdu4307

 

SAP: 671MS

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<math.h>
  4 #include<algorithm>
  5 #include<vector>
  6 #define LL long long
  7 using namespace std;
  8 
  9 const int maxn = 1011;
 10 const int maxm = 4000010;
 11 const LL inf = 9999999999;
 12 
 13 
 14 
 15 
 16 struct SAP{
 17     struct Edge{
 18     int v, next;
 19     LL w;
 20     }edge[maxm];
 21     int head[maxn];
 22 
 23     int cnt;
 24     int n, s, t;//n = t + 1;
 25 
 26 
 27     int pre[maxn],cur[maxn],dis[maxn];
 28     LL gap[maxn];
 29 
 30     void add(int u,int v,LL w)
 31     {
 32         edge[cnt].v=v;
 33         edge[cnt].w=w;
 34         edge[cnt].next=head[u];
 35         head[u]=cnt++;
 36         edge[cnt].v=u;
 37         edge[cnt].w=0;
 38         edge[cnt].next=head[v];
 39         head[v]=cnt++;
 40     }
 41 
 42     LL sap()
 43     {
 44         LL flow=0,aug=inf;
 45         int u;
 46         bool flag;
 47         for(int i=0;i<=n;i++)
 48         {
 49             cur[i]=head[i];
 50             gap[i]=dis[i]=0;
 51         }
 52         gap[s]=n;
 53         u=pre[s]=s;
 54         while(dis[s]<n)
 55         {
 56             flag=0;
 57             for(int &j=cur[u];j!=-1;j=edge[j].next)
 58             {
 59                 int v=edge[j].v;
 60                 if(edge[j].w>0&&dis[u]==dis[v]+1)
 61                 {
 62                     flag=1;
 63                     if(edge[j].w<aug) aug=edge[j].w;
 64                     pre[v]=u;
 65                     u=v;
 66                     if(u==t)
 67                     {
 68                         flow+=aug;
 69                         while(u!=s)
 70                         {
 71                             u=pre[u];
 72                             edge[cur[u]].w-=aug;
 73                             edge[cur[u]^1].w+=aug;
 74                         }
 75                         aug=inf;
 76                     }
 77                     break;
 78                 }
 79             }
 80             if(flag)
 81                 continue;
 82             int mindis=n;
 83             for(int j=head[u];j!=-1;j=edge[j].next)
 84             {
 85                 int v=edge[j].v;
 86                 if(edge[j].w>0&&dis[v]<mindis)
 87                 {
 88                   mindis=dis[v];
 89                   cur[u]=j;
 90                 }
 91             }
 92             if((--gap[dis[u]])==0)
 93                 break;
 94             gap[dis[u]=mindis+1]++;
 95             u=pre[u];
 96         }
 97 
 98         return flow;
 99 
100     }
101 
102     void init(int __n,int __s, int __t)
103     {
104         n = __n;
105         s = __s;
106         t = __t;
107         cnt = 0;
108         memset(head,-1,sizeof(head));
109     }
110 }Flow;
111 
112 int n;
113 LL B[maxn][maxn];
114 LL C[maxn];
115 LL BB[maxn];
116 int main()
117 {
118     int cas;
119     scanf("%d",&cas);
120     while  (cas--)
121     {
122         scanf("%d",&n);
123         int s = 0, t = n + 1;
124 
125         Flow.init(n+2,s,t);
126         LL sum = 0;
127         for (int i=1;i<=n;i++)
128         {
129             BB[i] = 0;
130             for (int j=1;j<=n;j++)
131             {
132                 scanf("%I64d",&B[i][j]);
133                 BB[i] += B[i][j];
134                 Flow.add(j,i,B[i][j]);
135             }
136             Flow.add(i,t,BB[i]);
137             sum += BB[i];
138         }
139         for (int i=1;i<=n;i++)
140         {
141             scanf("%I64d",&C[i]);
142             Flow.add(s,i, C[i]);
143         }
144 
145        // puts("dfs");
146         LL ans = sum - Flow.sap();
147 
148         printf("%I64d\n",ans);
149     }
150     return 0;
151 }
hdu4307

 

转载于:https://www.cnblogs.com/wangsouc/articles/3712066.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值