网络流24题总结和题解

大体按照难度阵营

 

t0 

1.飞行员配对方案问题 

这是个二分图匹配模板 但是这个输出方案套路还是要 掌握起来~

大概是 我们跑网络流 一定能获得两个东西

1.最大最小可行流数值和最大流数值

2.一个可行的跑的方案 这个方案的特点是按照加边顺序进行增广 也就是说 加边满足字典序时 就可以按字典序跑了

我们得到1 不停地增广 我们得到二 就是寻找跑满流量的正向边

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define maxn 10005
 5 #define inf 200000000
 6 int n,m,k=0,l,a,b,c,d[maxn],cur[maxn],visit[maxn],s=0,t;
 7 struct edge{int from,to,cap,flow;};vector<int>g[maxn];vector<edge>edges;
 8 void add_edge(int f,int t,int c){g[f].push_back(k);g[t].push_back(k+1);
 9     edges.push_back({f,t,c,0});edges.push_back({t,f,0,0});k+=2;
10 }bool bfs(){queue<int>q;q.push(s);for(int i=1;i<=t;i++)d[i]=inf;d[s]=0;
11     visit[s]=1,q.push(s);
12     while(!q.empty()){int u=q.front();q.pop();visit[u]=0;
13         for(int i=0;i<g[u].size();i++){edge &e=edges[g[u][i]];
14             if(e.cap>e.flow&&d[e.to]>d[u]+1){d[e.to]=d[u]+1;if(!visit[e.to])q.push(e.to),visit[e.to]=1;
15             }
16         }
17     }return d[t]!=inf;
18 }ll dfs(int x,int a){if(x==t||a==0)return a;ll f=0,flow=0;
19     for(int &i=cur[x];i<g[x].size();i++){edge &e=edges[g[x][i]];
20         if(d[e.to]==d[x]+1&&(f=dfs(e.to,min(e.cap-e.flow,a)))){
21             e.flow+=f,edges[g[x][i]^1].flow-=f,flow+=f,a-=f;
22         }
23     }return flow;
24 }ll mf(ll s,ll t){ll flow=0;
25     while(bfs()){memset(cur,0,sizeof(cur));
26         flow+=dfs(s,inf);
27     }return flow;
28 }int main(){cin>>m>>n;cin>>a>>b;t=n+1;
29     for(int i=1;i<=m;i++)add_edge(s,i,1);for(int i=m+1;i<=n;i++)add_edge(i,t,1);
30     while(a!=-1)add_edge(a,b,1),cin>>a>>b;
31     cout<<mf(s,t)<<endl;
32     for(int i=1;i<=m;i++)for(int j=0;j<g[i].size();j++){
33             edge &e=edges[g[i][j]];if(e.flow==1)cout<<i<<" "<<e.to<<endl;
34     }return 0;
35 }
View Code

 

2.负载平衡问题

这不知道跟网络流有个π关系

啊 毫无关系 结论套一下就行 结论还是要掌握起来的

代码吧

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=105;
 5 
 6 ll n,a[N],sum,s[N];
 7 
 8 int main()
 9 {
10     cin>>n;
11     for(int i=1;i<=n;i++)
12     
13     cin>>a[i],
14     
15     sum+=a[i];
16     
17     sum/=n;
18     
19     for(int i=1;i<=n;i++)
20     
21     a[i]-=sum,
22     
23     s[i]=s[i-1]+a[i];
24     
25     sort(s+1,s+n+1);
26     
27     sum=0;
28     
29     for(int i=1;i<=n;i++)
30     
31     sum+=abs(s[n/2+1]-s[i]);
32     
33     cout<<sum;
34     return 0;
35 }
View Code

 

t1

1.餐巾计划问题

首先费用流

这个题也不知道是不是我搞错了 bzoj好像数据范围不大对 是不是有网络流以外的做法 我也不得而知

这个题是个这样的模型:点代表天 每个天有s种决策 就拆为s个点 构造分层图 图与图之间链接操作边(边代表操作)

简单来说叫做

第一类:决策拆点

难度评价 思维难度 2 代码难度 2 总体较为中档

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 4005
 4 #define ll long long
 5 #define inf 214700000
 6 struct edge{int from,to,cap,flow,cost;};
 7 int k=0;vector<edge>edges;vector<int>g[maxn];
 8 void add_edge(int f,int t,int v,int cost){g[f].push_back(k),g[t].push_back(k+1),k+=2,edges.push_back({f,t,v,0,cost}),edges.push_back({t,f,0,0,-cost});}
 9 int n,m,visit[maxn],d[maxn],a[maxn],p[maxn],aa,b,c,dd,s,t,m1,t1,m2,t2,x;
10 ll sum=0,flow=0;
11 bool spfa(){for(int i=1;i<maxn;i++)d[i]=inf;a[s]=inf;
12     memset(visit,0,sizeof(visit));
13     queue<int>q;q.push(s),d[s]=0;visit[s]=1;
14     while(!q.empty()){int u=q.front();q.pop();visit[u]=0;
15         for(int i=0;i<g[u].size();i++){edge &e=edges[g[u][i]];
16             if(d[e.to]>d[u]+e.cost&&e.cap>e.flow){p[e.to]=g[u][i],a[e.to]=min(a[u],e.cap-e.flow),d[e.to]=d[u]+e.cost;
17                 if(!visit[e.to])q.push(e.to),visit[e.to]=1;
18             }
19         }        
20     }if(d[t]==inf)return 0;
21     flow+=1ll*a[t];
22     sum+=1ll*d[t]*a[t];int u=t;
23     while(u!=s){edges[p[u]].flow+=a[t];edges[p[u]^1].flow-=a[t];
24         u=edges[p[u]].from;
25     }return true; 
26 }
27 int main(){cin>>n;s=0,t=2*n+1;
28     for(int i=1;i<=n;i++){scanf("%d",&x);
29         add_edge(s,i,x,0);add_edge(i+n,t,x,0);
30     }scanf("%d%d%d%d%d",&m,&t1,&m1,&t2,&m2);
31     for(int i=1;i<=n;i++){
32         if(i+1<=n)add_edge(i,i+1,inf,0);if(i+t1<=n)add_edge(i,i+n+t1,inf,m1);
33         if(i+t2<=n)add_edge(i,i+n+t2,inf,m2);add_edge(s,i+n,inf,m);
34     }while(spfa());cout<<sum<<endl;
35 }
View Code

 

 

转载于:https://www.cnblogs.com/iboom/p/10045084.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 什么是Git?它有什么优点? Git是一款版本控制系统,它可以记录代码的历史变化,便于多人协作开发和管理代码。它的优点包括: - 分布式管理:每个开发者都可以拥有一份完整的代码仓库,不需要依赖中央服务器。 - 强大的分支和合并功能:可以轻松地创建和合并分支,便于团队协作和版本管理。 - 快速轻便:Git采用了一些高效的算法和数据结构,使得它的速度非常快。 - 安全性高:Git使用SHA-1算法来保证代码的完整性和安全性。 2. Git的三个区域分别是什么? Git的三个区域分别是工作区、暂存区和版本库。 - 工作区:保存了实际的文件,也就是我们编辑的文件。 - 暂存区:保存了即将提交到版本库的文件,也就是我们通过`git add`命令添加的文件。 - 版本库:保存了所有的提交历史和代码版本,也就是我们通过`git commit`命令提交到Git的代码仓库。 3. 如何创建一个新的分支并切换到这个分支? 可以使用`git branch`命令创建新分支,然后使用`git checkout`命令切换到新分支: ``` $ git branch new_branch # 创建新分支 $ git checkout new_branch # 切换到新分支 ``` 也可以使用`git checkout`命令的`-b`选项,一步完成创建和切换: ``` $ git checkout -b new_branch # 创建新分支并切换到新分支 ``` 4. 如何合并两个分支? 可以使用`git merge`命令合并两个分支: ``` $ git checkout master # 切换到要合并的分支(通常是主分支) $ git merge feature_branch # 合并另一个分支 ``` 在合并过程中,Git会自动检测两个分支的差异,并尝试自动合并代码。如果合并过程中发生冲突,需要手动解决冲突,然后再次执行`git merge`命令。 5. 如何撤销上一次提交? 可以使用`git revert`命令撤销上一次提交: ``` $ git revert HEAD # 撤销上一次提交 ``` 这会创建一个新的提交,用于撤销上一次提交的变更。如果需要撤销多个提交,可以使用`git revert`命令的`-n`选项,指定要撤销的提交数量。 6. 如何回退到某个提交? 可以使用`git reset`命令回退到某个提交: ``` $ git reset --hard commit_id # 回退到指定的提交 ``` 这会将当前分支回退到指定的提交,并重写工作区和暂存区的内容。这会丢失当前提交之后的所有提交记录,谨慎使用。 7. 如何查看提交历史? 可以使用`git log`命令查看提交历史: ``` $ git log # 查看提交历史 ``` 这会列出所有提交的记录,包括提交的哈希值、作者、时间、提交消息等信息。可以使用`--pretty`选项指定输出格式。 8. 如何查看文件的差异? 可以使用`git diff`命令查看文件的差异: ``` $ git diff file_path # 查看工作区与当前版本库的差异 $ git diff commit_a..commit_b file_path # 查看两个提交之间的差异 ``` 这会输出文件的变更内容,包括添加、修改、删除等操作。如果需要查看某个文件的历史变更记录,可以使用`git log`命令的`--follow`选项。 9. 如何从远程仓库拉取代码? 可以使用`git pull`命令从远程仓库拉取代码: ``` $ git pull origin master # 从远程仓库的主分支拉取代码 ``` 这会将远程仓库的代码拉取到本地,并自动合并到当前分支。如果需要从其他分支拉取代码,可以修改`origin master`为相应的分支名称。 10. 如何推送代码到远程仓库? 可以使用`git push`命令将代码推送到远程仓库: ``` $ git push origin master # 将代码推送到远程仓库的主分支 ``` 这会将当前分支的代码推送到远程仓库,并更新远程仓库的代码。如果需要推送到其他分支,可以修改`origin master`为相应的分支名称。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值