bzoj2597: [Wc2007]剪刀石头布(费用流)

本文介绍了一种使用网络流算法解决特定类型竞赛问题的方法。通过构建网络模型,并利用最小费用最大流算法,来找到使比赛结果中三元组数量最大化的方案。文中详细解释了如何构造网络模型以及算法实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

 

不得不说这思路真是太妙了

考虑能构成三元组很难,那我们考虑不能构成三元组的情况是怎么样

就是说一个三元组$(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 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9588354.html

基于Spring Boot搭建的一个多功能在线学习系统的实现细节。系统分为管理员和用户两个主要模块。管理员负责视频、文件和文章资料的管理以及系统运营维护;用户则可以进行视频播放、资料下载、参与学习论坛并享受个性化学习服务。文中重点探讨了文件下载的安全性和性能优化(如使用Resource对象避免内存溢出),积分排行榜的高效实现(采用Redis Sorted Set结构),敏感词过滤机制(利用DFA算法构建内存过滤树)以及视频播放的浏览器兼容性解决方案(通过FFmpeg调整MOOV原子位置)。此外,还提到了权限管理方面自定义动态加载器的应用,提高了系统的灵活性和易用性。 适合人群:对Spring Boot有一定了解,希望深入理解其实际应用的技术人员,尤其是从事在线教育平台开发的相关从业者。 使用场景及目标:适用于需要快速搭建稳定高效的在线学习平台的企业或团队。目标在于提供一套完整的解决方案,涵盖从资源管理到用户体验优化等多个方面,帮助开发者更好地理解和掌握Spring Boot框架的实际运用技巧。 其他说明:文中不仅提供了具体的代码示例和技术思路,还分享了许多实践经验教训,对于提高项目质量有着重要的指导意义。同时强调了安全性、性能优化等方面的重要性,确保系统能够应对大规模用户的并发访问需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值