线性规划与网络流24题

来源:互联网 发布:淘宝管控记录是什么 编辑:程序博客网 时间:2024/05/16 17:09

    本来很久之前就打算开始做这个专题,也没太多完整时间,现在集中做一下 http://220.166.52.162/oj/problemlist?p=8 这个oj上能评测

    建图是白色字体 全选就能看见。

   首先奉上我的模板,后面的题目都是用均采用这个模板。  


#include<stdio.h>#include<memory.h>#define INF 0x3f3f3f3f#define maxn 1100#define maxe 1000010int gap[maxn],dis[maxn],pre[maxn],cur[maxn];int size,n,head[maxn];struct Node{int c,v,next;Node(){}Node(int _v,int _c,int _next):v(_v),c(_c),next(_next){}}E[maxe];int sap(int s,int t) {memset(dis,0,sizeof(dis));memset(gap,0,sizeof(gap));for(int i=1;i<=n;i++)cur[i] = head[i];int u = pre[s] = s,maxflow = 0,aug = -1;gap[0] = n;while(dis[s] < n) {loop:for(int &i = cur[u]; i != -1; i = E[i].next) {int v = E[i].v;if(E[i].c && dis[u] == dis[v] + 1) {if(aug==-1 || aug>E[i].c)aug=E[i].c;pre[v] = u;u = v;if(v == t) {maxflow += aug;for(u = pre[u];v != s;v = u,u = pre[u]) {E[cur[u]].c -= aug;E[cur[u]^1].c += aug;}aug = -1;}goto loop;}}int mindis = n;for(int i = head[u]; i != -1 ; i = E[i].next) {int v = E[i].v;if(E[i].c && mindis > dis[v]) {cur[u] = i;mindis = dis[v];}}if( (--gap[dis[u]]) == 0)break;gap[ dis[u] = mindis+1 ] ++;u = pre[u];}return maxflow;}void add(int u,int v,int c,int cc = 0) {E[size] = Node(v,c,head[u]);head[u] = size++;E[size] = Node(u,cc,head[v]);head[v] = size++;}void init(){memset(head,-1,sizeof(head));size=0;}


    第一题 飞行员配对方案问题

    建图:    二分图最大匹配   新建源汇点s和t,s到所有外籍飞行员连一条容量是1的边,所有英国飞行员到t连一条容量是1的边。

   代码当中只有建图部分。

int f,sum;int edge,uu[5100],vv[5100];int main(){int s,t;int i,u,v;freopen("D:\\in.txt","r",stdin);scanf("%d%d",&f,&sum);init();edge=0;while(scanf("%d%d",&u,&v),u+v!=-2){add(u,v,1);uu[edge]=u;vv[edge]=v;edge++;}n=sum+2;s=n-1;t=n;for(i=1;i<=f;i++)add(s,i,1);for(i=f+1;i<=sum;i++)add(i,t,1);printf("%d\n",sap(s,t));for(i=0;i<edge;i++)if(0 == E[2*i].c)printf("%d %d\n",uu[i],vv[i]);return 0;}



 太空飞行计划问题

 建图:最大权闭合子图,正点权的点全部从s到该点建一条流量是权值的边,负点权的点全部从该点建一条容量是绝对值的边到t,其他的边容量变为无穷大。

对于输出解,从s点开始在残留网络里面染色,确定割集,这个割集就代表了一个选择方案。


他们oj一直上不去 更新先到这里吧 等以后oj能评测再说。或者考虑自己写一个spj。


第三题 最小路径覆盖问题

 建图: DAG的最小路径覆盖问题。每个点拆成两个点x和x',对于一条A->B,那么就建成,a->b',然后跑二分图最大匹配就好。


第四题 魔术球问题

 建图:跟上题一样,也是一道DAG的最小路径覆盖问题,首先二分能放置的球的数目,然后如果判定n个柱子能否放下x个球,把每个球看成一个顶点,对于任意两个球,如果他们相加为平方数,那么就从小的到大的那个数连一条边,然后就构成了DAG,然后求最小路径覆盖,就是需要的柱子数目。


第五题 圆桌问题

 建图:裸的最大流,将每个单位和每个餐厅都建成一个顶点,从每个单位连接到每个餐厅一条容量是1的边,代表这个单位可以派一个人去某个餐厅吃饭,然后从s点到每个单位连接一条容量是单位人数的边,作为限制,同样的每个餐厅连接一条容量是餐厅用餐人数的边到t,跑s到t之间的最大流,如果能跑到人数之和,就是满流,那么就有解,否则就是无解。


第六题最长递增子序列问题

 建图:应用分层图的思想,是的网络流跑出来的路径均是符合我们想法的。

    第一问 先做一次dp,同时记录下到每个点最长递增是多少。

    第二问,然后通过这个分层图建图,每个元素拆成两个顶点,i.a和i.b,建立从i.a->i.b容量是1的边, 作为约束条件,每个顶点只能被使用一次,然后s到所有的第一层的i.a建立容量是1的边,同样,最高层的i.b建立到t的容量是1的边,这样跑出来之后就是答案。

    第三问,因为我们这里第一个和最后一个可以使用多次,所以就撤销掉他们的约束条件。将(s,i.a),(i.a,i.b), (n.a,n.b) (n.b,t) 这四条边修改为最大,当然如果不存在就不用修改了。


第七题 试题库问题

 建图:裸的最大流,将每道题目和每个类别建成一个顶点,然后从每个题目连一条容量是1的边到它属于的类别(到每个类别连一条),然后从s到每个题目连一条容量是1的边,从每个类别连一条容量是需要题目数的边,那么跑一次s到t的最大流就是答案。


第八题 机器人路径规划问题

 建图:


第九题 方格取数问题

 建图:先假设所有点我们都已经全部选择了,现在我们要舍弃一些点,使得任意我们选取的两个点之间不相邻,将整个图奇偶染色, 从每个奇点连一条容量是无穷大的边到偶点,然后从s到奇点连接一条容量是数字的边,同样从偶点连接一条容量是数字的边到t,然后从s到t跑一次最大流,解的输出还是老方法采用染色法找一个割集。


第十题 餐巾计划问题

 建图:非常好的一道题目,想了很久,刚开始的第一感觉就是费用流,然后就是每天的餐巾来源有3个,一个就是今天新买的,还有今天快洗出来的,第三种今天慢洗出来的,那么最终这个流就是流向了t,那么我们这里就存在一个问题,一个流结束在t点之后,相当于今天的毛巾就消失了,但实际上,这些毛巾只是变成了脏毛巾,还能再用,没做,我们可以每天手动补上这么多的脏毛巾,反正每天产生的脏毛巾数是确定的,构图不再是梦想。

        将每天拆成二倍点,i.a 和i.b,i.a理解为脏毛巾,i.b理解为干净毛巾,然后从s到i.a 连接一条容量是当天需求量的边,费用0,代表每天可以免费得到这么多脏毛巾,i.b连接一条容量是当天需求量费用流的边到t,意味着每天需要消耗这么多的新毛巾,i.a连接一条到i+1.a 的容量无穷大,费用0 的边,那么就意味着当天的脏毛巾可以免费留到第二天再去洗,然后就是i.a 到i+d1.b 容量无穷, 费用c1的边,代表快洗,i.a 到i+d2.b 容量无穷, 费用c2的边,代表慢洗。跑一次最小费用流就可以了。

for(i=1;i<=N;i++)scanf("%d",need+i);init();n=2*N+2;s=n-1;t=n;for(i=1;i<=N;i++){add(s,i+N,INF,p);add(i+N,t,need[i],0);if(i+d1 <= N)add(i,i+d1+N,INF,c1);if(i+d2 <= N)add(i,i+d2+N,INF,c2);}for(i=1;i<=N;i++){add(s,i,need[i],0);if(1 != i)add(i-1,i,INF,0);}mcmf(s,t);printf("%d\n",mincost);



第十一题 航空路线问题

 建图:比较简单的费用流,因为有每个城市只能访问一次的约束条件,所以先将城市拆点,设最西面的点位S,最东面的点为T,对于每个点i.a->i.b建立一条容量是1费用是0的边,特别的对于S和T两个点,s.a->s.b和t.a->t.b 建立容量是2,费用为0的边,对于原图中的每条航线,u->v,(u在v的西面),那么我们就建立从u.b->v.a 和 边,容量是1,费用是花费,最后跑一次从s.a 到 t.b 的最小费用最大流,如果满流不到2 那么就是无解,否则费用就是最小代价。


第十二题 软件补丁问题

 建图:状压完100万个状态,状态之间有转移,同时所有的时间都是正的,直接最短路搞起,spfa,dijkstra任君选择。



第十三题 星际转移问题

 建图:  满流判定+二分

        还是分层图,分层图用处多多,有一些情况下我们无法让网络流跑出符合我们要求的流出来,可能会违反规则,分层图就派上用场啦,使得跑出来的都是在我们规划下的路径,就像在这道题当中,因为飞船是按照一定的规则来运动,而且所有的单位时间都是一样的,直接建成分层图, 如果a->b 那么就是a和下一层的b相连,容量是限制飞船容量的。而且人可以停在某个空间站不懂,所以就是该层a到下一层的a建立一条容量是无穷的边,建立一条s到第一层的地球容量是人数的边,同时最后一层的月球到t连一条容量无穷得边,这样满流就是可以在规定时间内转移完毕。


第十四题 孤岛营救问题

 建图:   总共有P了类钥匙,那么就状压之后成为2^P个状态,代表钥匙取到的情况,然后直接扩展状态跑最短路就好。



第十五题 汽车加油行驶问题

 建图:跟上一道一样,仔细观察发现,其实题目中的K是小于10的,所以我们直接扩展状态,代表到某点还有多少油作为一个状态直接跑最短路。



第十六题 数字梯形问题

 建图:

规则1,直接从起点连接m条容量是1的边到第一排的点,然后之后把所有的点拆成二倍点,加上容量限制1,然后每个点到下面一排的两个相邻的点,加上一条容量是1的边就好。

规则2,把容量限制去掉,不用拆点,然后点之间的连边还是容量1。

规则3,因为不限制路径,所以依旧不需要去拆点,而且点之间的连边容量INF,但是起点到第一排点连接m条容量是1的边就好。



第十七题 运输问题

 建图:直接建成二部图,然后在两排点之间连的边就是他们的费用,然后分别跑一次最小费用流和最大费用流,就是两种情况下的答案。



第十八题 分配问题

 建图:建立二部图模型,然后在之间建边,分别进行最小费用流和最大费用流。


第十九题 负载平衡问题

 建图:每个仓库拆成两个点,S到X连接一条容量是原有存货量的边,X到X‘连接一条容量是无穷,费用为0的边,同时表示转移,X’连接一条容量无穷,费用为1的边到周围两个点Y,那么每个X‘连接一条容量是平均值,费用为0的边,跑一次最小费用流。


第二十题 深海机器人问题

 建图:因为这道题目的限制是说每条的价值只能获得一次,所以说我们这里将边进行分类加两条,图中的每个网格点看成网络图中的顶点,然后每两个点之间之间加一条容量是1,费用是价值的边,还有一条容量是无穷费用为零的边,然后每个起始点和终点加好对应的边,跑一次最大费用流。


第二十一题 最长k可重区间集问题

 建图:第一种,离散化,在每两个相邻点之间建立一条容量是K,费用为相邻长度的边,然后对于每一个区间,从S建立一条容量是1费用为0的边到入口处,出口处建立一条容量是1,费用为0的边到T.最后加一条容量是无穷,费用为0的边从S到T.用来保证选取到最优解而不是流最大解。

第二种,离散化,在每相邻两个点之间建立一条容量是无穷,费用为0的边,然后对于每个区间,建立一条容量是1,费用是长度的边,代表选择了这条边,然后在最左边的起点处加上一条容量是K,费用为0的边,在最右边的出口处加上一条容量是K,费用是0的边,然后在S和T之间跑一次最大费用流就可以。



第二十二题 最长k可重线段集问题

 建图:只能采用上一题中的第二种建图方法,方法一致。



第二十三题 火星探险问题

 建图:将图中的所有点拆成二倍点,然后从i.b连接一条容量是无穷的边到南方和东方的两个点.a ,然后对于所有的岩石从i.a到 i.b 连接一条容量是1,费用是1的边,加上一条容量无线,费用为0的边,对于所有的空地,连接一条容量为无穷,费用为0的边。

然后从起点到终点跑一次最大费用流。(应该如何去输出路径)



第二十四题 骑士共存问题

 建图:先奇偶染色,就变成了二部图,然后就是与方格取数一样的做法,每个奇点到相邻的偶点连接一条容量为无穷大的边,用来保证不能被割掉,然后s到奇点建立一条容量是1的点,偶点到t建一条容量是1的边,s到t最大流就是答案。

原创粉丝点击