bzoj2597: [Wc2007]剪刀石头布(费用流)
不得不说这思路真是太妙了
考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样
就是说一个三元组(a,b,c),其中a赢两场,b赢一场,c没有赢
所以如果第i个人赢了w_i场,那么总共的不能构成的三元组就是\sum_i{w_i*(w_i-1)}{2}
最大化满足的数量,就是最小化不满足的数量,就是最小化上面那个式子
那么我们考虑构建网络流
建源汇
对第i个人,从它向汇点连容量为n的边
对于每一对i,j之间的比赛建一个点C_{i,j},如果这场比赛尚未进行,那么源点向C_{i,j}连容1费0的边,C_{i,j}向i和j连容1费0$的边,表示这场比赛只能改变一个点的赢的场数
我们要最小化上式,那么我们考虑在费用上做文章
每个点i向汇点连边,但因为费用的增加是一次比一次大的,所以我们考虑把这条边拆成n条边,容量为1费用分别为0,1,2...
因为费用流每一次都先增广最小的费用,所以只要求出最小费用最大流即可
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 9 char buf[1<<21],*p1=buf,*p2=buf; 10 inline int read(){ 11 #define num ch-'0' 12 char ch;bool flag=0;int res; 13 while(!isdigit(ch=getc())) 14 (ch=='-')&&(flag=true); 15 for(res=num;isdigit(ch=getc());res=res*10+num); 16 (flag)&&(res=-res); 17 #undef num 18 return res; 19 } 20 const int N=50005,M=100005; 21 int head[N],Next[M],ver[M],edge[M],cost[M],tot=1; 22 inline void add(int u,int v,int e,int c=0){ 23 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,cost[tot]=c; 24 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0,cost[tot]=-c; 25 } 26 int dis[N],vis[N],cur[N],S,T,ans; 27 queue<int> q; 28 bool spfa(){ 29 memset(dis,-1,sizeof(dis)); 30 memset(vis,0,sizeof(vis)); 31 memcpy(cur,head,sizeof(head)); 32 q.push(T),dis[T]=0,vis[T]=1; 33 while(!q.empty()){ 34 int u=q.front();q.pop(),vis[u]=0; 35 for(int i=head[u];i;i=Next[i]) 36 if(edge[i^1]){ 37 int v=ver[i],c=cost[i]; 38 if(dis[v]<0||dis[v]>dis[u]-c){ 39 dis[v]=dis[u]-c; 40 if(!vis[v]) vis[v]=1,q.push(v); 41 } 42 } 43 } 44 return ~dis[S]; 45 } 46 int dfs(int u,int limit){ 47 if(!limit||u==T) return limit; 48 int flow=0,f;vis[u]=1; 49 for(int i=cur[u];i;cur[u]=i=Next[i]){ 50 int v=ver[i]; 51 if(dis[v]==dis[u]-cost[i]&&!vis[v]&&(f=dfs(v,min(limit,edge[i])))){ 52 flow+=f,limit-=f; 53 edge[i]-=f,edge[i^1]+=f; 54 ans-=f*cost[i]; 55 if(!limit) break; 56 } 57 } 58 vis[u]=0; 59 return flow; 60 } 61 void zkw(){while(spfa()) dfs(S,inf);} 62 int mp[105][105],win[105][105],n,cnt; 63 int main(){ 64 //freopen("testdata.in","r",stdin); 65 n=read(); 66 for(int i=1;i<=n;++i) 67 for(int j=1;j<=n;++j) 68 mp[i][j]=read(); 69 S=0,cnt=n; 70 for(int i=1;i<=n;++i) 71 for(int j=1;j<i;++j){ 72 add(S,++cnt,1); 73 if(mp[i][j]==0||mp[i][j]==2) add(cnt,i,1),win[j][i]=tot-1; 74 if(mp[i][j]==1||mp[i][j]==2) add(cnt,j,1),win[i][j]=tot-1; 75 } 76 T=cnt+1; 77 for(int i=1;i<=n;++i) 78 for(int j=0;j<n;++j) 79 add(i,T,1,j); 80 ans=n*(n-1)*(n-2)/6; 81 zkw(); 82 printf("%d\n",ans); 83 for(int i=1;i<=n;++i){ 84 for(int j=1;j<=n;++j) 85 printf("%s%d",j==1?"":" ",!win[i][j]||edge[win[i][j]]?0:1); 86 putchar(10); 87 } 88 return 0; 89 }
深深地明白自己的弱小
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步