线性规划与网络流24题●09方格取数问题&13星际转移问题

●(做codevs1908时,发现测试数据也涵盖了1907,想要一并做了,但因为“技术”不佳,搞了一上午)

●09方格取数问题(codevs1907  方格取数3)

  • 想了半天,也没成功建好图;
  • 无奈下参考题解,说是本题要求二分图点权最大独立集,然后可以由结论:“最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流”转化到求最大流(我真的很懵逼,但又感觉很有道理);
  • 下面附上solution:(自己领悟吧)
  • (不懂那个鬼结论的我就用那个结论建了个图,跑了个Dinic。)

13星际转移问题(codevs 1908)

  • (这个题的要比上一个好想一些。(因为上一题的鬼结论我真不知道))
  • 思路:
    • 本题的建图比较有趣,要把每个空间站按天数进行建点和连边;
    • 建图:
      • 1.原点(s)到地球(ear)有一条容量为k的边;(表示要送出k个人民)
      • 2.月球(yue)到汇点(t)有一条容量为INF的边;
      • 3.每个空间站的前一天的点到该空间站的后一天有一条容量为INF的边;(表示人民可以待在空间站里度过一天又一天)
      • 4.若一个飞船在前一天在某一空间站(或地球),后一天在另一个空间站(或月球),则在对应的两个点间连一条有向边,容量为飞船的载重;(表示前一天某一空间站(或地球)的几个人民可以通过一个飞船坐到后一天的另一个空间站(或月球);
    • 以题目的样例为例,上一张图帮助理解;
    • 上图中:
      • 方框为点,里面的数字为编号;
      • 黑色箭头为边,上的数字为容量,(未标的均为INF);
      • 红色路径为最大的可行流。
    • (建图方法解决后,但还有一个问题,Day是未知的,该怎么确定点有多少呢?)
    • 方法:枚举天数或二分天数,然后跑个最大流判断是否能将人民送完(即汇点的流入量是否等于k);
    • 选择:枚举天数:
    • 原因:改图比较特殊,若用枚举天数的方法,只需每次在前一次的图上加新点,连新边即可,一直到找到答案。若用二分的话,则需要每次重新建图。
    • (当然,在开始枚举天数之前,先用并查集检查一下人民能否从地球到月球。)
    • 总:枚举+Dinic(找最大流)+并查集(e,只是用来检查的)

●代码(为了AC掉codevs1908,把两份代码怼到一起了):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define INF 0x3f3f3f3f
    using namespace std;
    int n,m,k,yue=1,ear=2,sz=4,ent=2,aim,tot,s,t;
    int sps[30][30],cw[30][2],ld[30],ls[30],head[30000],h[30000],q[30000];
    int fa[30];
    struct edge{
    	int to,cap,next;
    }e[300000];
    bool special_read()
    {
    	char s[100];
    	gets(s);
    	int a[4]={0},o=1;
    	int len=strlen(s);
    	for(int i=0;i<len;i++)
    	{
    		if(‘0‘<=s[i]&&s[i]<=‘9‘) a[o]=a[o]*10+s[i]-‘0‘;
    		else if(a[o]) o++;
    	}
    	n=a[1];m=a[2];
    	return k=a[3];
    }
    int read(int &o)
    {
    	int x=0,f=1; char ch=getchar();
    	while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1;ch=getchar();}
    	while(‘0‘<=ch&&ch<=‘9‘) {x=x*10+ch-‘0‘;ch=getchar();}
    	o=x*f;
    }
    void add_edge(int u,int v,int cap)
    {
    	e[ent]=(edge){v,cap,head[u]};head[u]=ent++;
    	e[ent]=(edge){u,0,head[v]};head[v]=ent++;
    }
    void make_new_edge(int day)
    {
    	for(int i=3;i<=n+3-1;i++) add_edge(ld[i],++sz,INF),ld[i]=sz;
    	for(int i=1;i<=m;i++)
    	{
    		int t=day%cw[i][1],o=sps[i][t];
    		if(o==ear) add_edge(ear,++sz,cw[i][0]),ls[i]=sz;
    		else if(o==yue) add_edge(ls[i],yue,cw[i][0]),ls[i]=0;
    		else
    		{
    			if(ls[i])add_edge(ls[i],ld[o],cw[i][0]);
    			ls[i]=ld[o];
    		}
    	}
    }
    bool bfs(int s,int t)
    {
    	memset(h,0,sizeof(h));
    	int l=0,r=1;q[1]=s;h[s]=1;
    	while(l<r)
    	{
    		int u=q[++l];
    		for(int i=head[u];i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if(h[v]||!e[i].cap) continue;
    			h[v]=h[u]+1; q[++r]=v;
    		}
    	}
    	return h[t];
    }
    int dfs(int u,int res,int t)
    {
    	if(u==t) return res;
    	int flowout=0,f;
    	for(int i=head[u];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(!e[i].cap||h[v]!=h[u]+1) continue;
    		f=dfs(v,min(res,e[i].cap),t);
    		e[i].cap-=f; e[i^1].cap+=f;
    		flowout+=f; res-=f;
    		if(!res) break;
    	}
    	if(!flowout) h[u]=-1;
    	return flowout;
    }
    int Dinic(int s,int t)
    {
    	while(bfs(s,t))
    	{
    		aim+=dfs(s,INF,t);
    	}
    	return aim;
    }
    void check_and_add(int a,int b,int c,int d)
    {
    	c+=a; d+=b;
    	if(c==0||c==n+1||d==0||d==m+1) return;
    	int u=(a-1)*m+b,v=(c-1)*m+d;
    	add_edge(u,v,INF);
    }
    int find(int x)
    {
    	if(fa[x]!=x) return fa[x]=find(fa[x]);
    	return x;
    }
    void unio(int x,int y)
    {
    	int fx=find(x),fy=find(y);
    	if(fx!=fy) fa[fy]=fx;
    }
    void _1908()
    {
    	for(int i=1;i<=25;i++) fa[i]=i;
    	for(int i=1;i<=m;i++)
    	{
    		read(cw[i][0]);read(cw[i][1]);
    		for(int j=0;j<cw[i][1];j++)
    		{
    			read(sps[i][j]);
    			sps[i][j]+=2;
    			if(j)
    			for(int jj=0;jj<j;jj++)
    			 unio(sps[i][jj],sps[i][j]);
    		}
    	}
    	if(find(yue)!=find(ear)) printf("0");
    	else
    	{
    		int day=0;
    		add_edge(3,ear,k); add_edge(yue,4,INF);
    		for(int i=3;i<=n+3-1;i++) ld[i]=++sz;
    		for(int i=1;i<=m;i++)
    		{
    			int o=sps[i][0];
    			if(o==ear) add_edge(ear,++sz,cw[i][0]),ls[i]=sz;
    			else if(o!=yue) ls[i]=ld[o];
    		}
    		while(1)
    		{
    			++day;
    			make_new_edge(day);
    			if(Dinic(3,4)==k) { printf("%d",day); break;}
    		}
    
    	}
    }
    void _1907()
    {
    	int x,co=0;
    	s=n*m+1;t=n*m+2;
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    	{
    		co=(i+j)%2;
    		int u=(i-1)*m+j;scanf("%d",&x); tot+=x;
    		if(!co)
    		{
    			add_edge(s,u,x);
    			check_and_add(i,j,-1,0);
    			check_and_add(i,j,1,0);
    			check_and_add(i,j,0,-1);
    			check_and_add(i,j,0,1);
    		}
    		else add_edge(u,t,x);
    	}
    	printf("%d",tot-Dinic(s,t));
    }
    int main()
    {
    	if(special_read()) _1908();
    	else _1907(); 
    
    	return 0;
    }
时间: 2024-10-11 11:20:05

线性规划与网络流24题●09方格取数问题&13星际转移问题的相关文章

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数

【网络流24题】方格取数问题

Description 在一个有m * n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. Input 第1 行有2 个正整数m和n,分别表示棋盘的行数和列数. 接下来的m行,每行有n个正整数,表示棋盘方格中的数. Output 将取数的最大总和输出 Sample Input 3 3 1 2 3 3 2 3 2 3 1 Sample Output

「网络流 24 题」方格取数

大意: 给定$n*m$棋盘, 每个格子有权值, 不能选择相邻格子, 求能选出的最大权值. 二分图带权最大独立集, 转化为最小割问题. S与$X$连边权为权值的边, $X$与$Y$之间连$INF$, $Y$与$T$连边权为权值的边. 则最大权值为总权值-最小割. 残量网络中与$S$相连的或与$T$相连的表示选择, 否则表示不选. #include <iostream> #include <sstream> #include <algorithm> #include <

题解:线性规划与网络流24题 T2 太空飞行计划问题

太空飞行计划问题 问题描述 W教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,-,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,-In}.实验Ej 需要用到的仪器是I的子集Rj ∈ I.配置仪器Ik的费用为ck美元.实验Ej 的赞助商已同意为该实验结果支付pj 美元.W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大.这里净收

线性规划与网络流24题第2题 太空飞行计划 最小割

/** 题目: 线性规划与网络流24题第2题 太空飞行计划 最小割 链接:http://www.cogs.pro/cogs/problem/problem.php?pid=727 题意:lv 思路:最大点权独立集(点集中任意两个点没有边相连,且点权和最大)=点权总和-最小点权覆盖集. 将实验和仪器看做节点. 实验放在二分图的左边, s->x, cap = 实验利润. 仪器放在右边, x->t, cap = 仪器费用. 如果实验u的进行需要仪器v,u->v, cap = INF. ans

线性规划与网络流24题 索引

线性规划与网络流24题 可参考 网络流24题分类

【网络流】hdu 1569 方格取数(2)

/* 和1565一样: 总点数的权 - 最小覆盖点集 = 最大独立集 -------------------------------------- void add(int u, int v, int f)加边 { e[ct].u = u; e[ct].v = v; e[ct].f = f; next[ct] = first[u]; first[u] = ct++; e[ct].u = v; e[ct].v = u; e[ct].f = 0; next[ct] = first[v]; first

【线性规划与网络流24题】汽车加油行驶问题 分层图

汽车加油行驶问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 给定一个 N*N的方形网格,设其左上角为起点◎,坐标为( 1,1),X轴向右为正, Y轴向下为正,每一个方格边长为 1,如图所看到的.一辆汽车从起点◎出发驶向右下角终点▲,其坐标为( N,N).在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油.汽车在行驶过程中应遵守例如以下规则: (1)汽车仅仅能沿网格边行驶,装满油后能行驶 K条网格边.出发时汽车已装满油,在起点与终

【线性规划与网络流24题】孤岛营救问题 分层图

孤岛营救问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为 N行,东西方向被划分为 M列,于是整个迷宫被划分为 N×M个单元.每一个单元的位置可用一个有序数对 (单元的行号,单元的列号)来表示.南北或东西方向相邻的 2个单元之间可能