Gym - 102346G Getting Confidence 最小费用最大流

Gym - 102346G Getting Confidence

题意:n*n的格子,每个格子上有一个数,要求每行每列都只能拿一个数,使得乘积最大,然后输出每列选择的是第几行的数。

如果是加法的话,那么很明显,就是一个网络流。可是,现在是乘法怎么办,很简单,直接取log,那么乘法便转换成了加法,然后就可以建图。

每行每列只能取一个数,就相当于行列是拆开的点,因为需要输出的是列的信息,那么源点向每一列建一条流量为1,费用为0的边,而每一行向汇点建一条流量为1,费用为0的边。

再对于每个格子,每一列向它这一列的格子建一条流量为1,费用为0的点,而每个格子向它所在的行建一条流量为1,费用为-log(格子上的数)的边。

最后跑一遍最小费用最大流,看一下每一列的那条边流量为0

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<queue> 
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=2e4+11,M=1e6+11,inf=1e9+7;
 7 struct Side{
 8     int v,ne,w;
 9     double val;
10 }S[M<<1];
11 double dis[N];
12 int n,sn,sb,se,head[N],vis[N],flow[N],lu[N];
13 void init(){
14     sn=0;
15     sb=0;se=n*n+2*n+1;
16     for(int i=sb;i<=se;i++) head[i]=-1;
17 }
18 void add(int u,int v,int w,double val){
19     S[sn].w=w;S[sn].val=val;
20     S[sn].v=v;S[sn].ne=head[u];
21     head[u]=sn++;
22 }
23 void addE(int u,int v,int w,double val){
24     add(u,v,w,val);add(v,u,0,-val); 
25 }
26 bool spfa(){
27     queue<int> q;
28     for(int i=sb;i<=se;i++){
29         dis[i]=inf;
30         vis[i]=0;
31         flow[i]=inf;
32         lu[i]=-1;
33     }
34     dis[sb]=0;
35     vis[sb]=1;
36     q.push(sb);
37     int u,v;
38     while(!q.empty()){
39         u=q.front();q.pop();vis[u]=0;
40         for(int i=head[u];~i;i=S[i].ne){
41             v=S[i].v;
42             if(S[i].w>0&&dis[v]>dis[u]+S[i].val){
43                 lu[v]=i;
44                 dis[v]=dis[u]+S[i].val;
45                 flow[v]=min(flow[u],S[i].w);
46                 if(!vis[v]){
47                     vis[v]=1;
48                     q.push(v);
49                 }
50             }
51         }
52     }
53     return dis[se]!=inf; 
54 }
55 void mfml(){
56     int ans=0,ansc=0;
57     while(spfa()){
58         ans+=flow[se];
59         ansc+=flow[se]*dis[se];
60         for(int i=lu[se];~i;i=lu[S[i^1].v]){
61             S[i].w-=flow[se];
62             S[i^1].w+=flow[se];
63         }
64     }
65 }
66 int main(){
67     while(~scanf("%d",&n)){
68         init();;
69         for(int i=1;i<=n;i++){
70             addE(sb,n*n+n+i,1,0.0);
71             addE(n*n+i,se,1,0.0);
72         }
73         for(int i=1,x;i<=n;i++){
74             for(int j=1;j<=n;j++){
75                 scanf("%d",&x);
76                 addE(n*n+n+j,(i-1)*n+j,1,0.0);
77                 addE((i-1)*n+j,n*n+i,1,-log(1.0*x));
78             }
79         }
80         mfml();
81         for(int i=1;i<=n;i++)
82             for(int j=head[n*n+n+i];~j;j=S[j].ne){
83                 if(S[j].w||S[j].v==sb) continue;
84                 printf("%d%c",(S[j].v-1)/n+1," \n"[i==n]);
85                 break;
86             }
87     }
88     return 0;
89 } 
log转乘为加

猜你喜欢

转载自www.cnblogs.com/LMCC1108/p/11719041.html