LuoguP2754 [CTSC1999]家园(分层图,最大流)
Posted blog-dr-j
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LuoguP2754 [CTSC1999]家园(分层图,最大流)相关的知识,希望对你有一定的参考价值。
题目背景
none!
题目描述
由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。
现有 n 个太空站位于地球与月球之间,且有 m 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而每艘太空船 i 只可容纳 H[i]个人。每艘太空船将周期性地停靠一系列的太空站,例如:(1,3,4)表示该太空船将周期性地停靠太空站 134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为 1。人们只能在太空船停靠太空站(或月球、地球)时上、下船。
初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。
对于给定的太空船的信息,找到让所有人尽快地全部转移到月球上的运输方案。
输入输出格式
输入格式:
第 1 行有 3 个正整数 n(太空站个数),m(太空船个数)和 k(需要运送的地球上的人的个数)。其中 n<=13 m<=20, 1<=k<=50。
接下来的 m 行给出太空船的信息。第 i+1 行说明太空船 pi。第 1 个数表示 pi 可容纳的人数 Hpi;第 2 个数表示 pi 一个周期停靠的太空站个数 r,1<=r<=n+2;随后 r 个数是停靠的太空站的编号(Si1,Si2,…,Sir),地球用 0 表示,月球用-1 表示。
时刻 0 时,所有太空船都在初始站,然后开始运行。在时刻 1,2,3…等正点时刻各艘太空船停靠相应的太空站。人只有在 0,1,2…等正点时刻才能上下太空船。
输出格式:
程序运行结束时,将全部人员安全转移所需的时间输出。如果问题
无解,则输出 0。
解题思路:
假如说告诉你多少天,问转移人口,那是不是会好一些,
按时间分层,不同层相同点间按照时间方向建$inf$的边,
跑一边最大流,源点是0时刻的地球,汇点是T时刻的月球。
最大流就是人口。
所以枚举判断好了。
代码:
1 #include<queue>
2 #include<cstdio>
3 #include<vector>
4 #include<cstring>
5 #include<algorithm>
6 const int oo=0x3f3f3f3f;
7 struct pnt{
8 int hd;
9 int lyr;
10 int now;
11 }p[10000];
12 struct ent{
13 int twd;
14 int lst;
15 int vls;
16 }e[1000000];
17 int cnt;
18 int n,m,k;
19 int s,t;
20 int size;
21 int H[1000];
22 int fa[1000];
23 std::queue<int>Q;
24 std::vector<int>st[1000];
25 void ade(int f,int t,int v)
26 {
27 cnt++;
28 e[cnt].twd=t;
29 e[cnt].vls=v;
30 e[cnt].lst=p[f].hd;
31 p[f].hd=cnt;
32 return ;
33 }
34 bool Bfs(void)
35 {
36 while(!Q.empty())
37 Q.pop();
38 for(int i=1;i<=size;i++)
39 p[i].lyr=0;
40 p[s].lyr=1;
41 Q.push(s);
42 while(!Q.empty())
43 {
44 int x=Q.front();
45 Q.pop();
46 for(int i=p[x].hd;i;i=e[i].lst)
47 {
48 int to=e[i].twd;
49 if(p[to].lyr==0&&e[i].vls>0)
50 {
51 p[to].lyr=p[x].lyr+1;
52 if(to==t)
53 return true;
54 Q.push(to);
55 }
56 }
57 }
58 return false;
59 }
60 int Dfs(int x,int fll)
61 {
62 if(x==t)
63 return fll;
64 for(int& i=p[x].now;i;i=e[i].lst)
65 {
66 int to=e[i].twd;
67 if(p[to].lyr==p[x].lyr+1&&e[i].vls>0)
68 {
69 int ans=Dfs(to,std::min(fll,e[i].vls));
70 if(ans>0)
71 {
72 e[i].vls-=ans;
73 e[((i-1)^1)+1].vls+=ans;
74 return ans;
75 }
76 }
77 }
78 return 0;
79 }
80 int Dinic(void)
81 {
82 int ans=0;
83 while(Bfs())
84 {
85 for(int i=1;i<=size;i++)
86 p[i].now=p[i].hd;
87 int dlt;
88 while(dlt=Dfs(s,oo))
89 ans+=dlt;
90 }
91 return ans;
92 }
93 int finf(int x)
94 {
95 return fa[x]==x?x:fa[x]=finf(fa[x]);
96 }
97 int main()
98 {
99 // freopen("a.in","r",stdin);
100 scanf("%d%d%d",&n,&m,&k);
101 for(int i=1;i<=n+m+2;i++)fa[i]=i;
102 for(int i=1;i<=m;i++)
103 {
104 scanf("%d",&H[i]);
105 int tmp;
106 scanf("%d",&tmp);
107 for(int j=1;j<=tmp;j++)
108 {
109 int tl;
110 scanf("%d",&tl);
111 if(tl==0)tl=n+1;
112 if(tl==-1)tl=n+2;
113 st[i].push_back(tl);
114 int f1=finf(tl);
115 int f2=finf(n+2+i);
116 if(f1!=f2)
117 fa[f1]=f2;
118 }
119 }
120 if(finf(n+1)!=finf(n+2))
121 {
122 printf("%d
",0);
123 return 0;
124 }
125 s=n+1;
126 int N;
127 int popu=0;
128 for(N=0;;N++)
129 {
130 if(N)
131 {
132 for(int i=1;i<=n+m+2;i++)
133 {
134 ade((N-1)*(n+m+2)+i,N*(n+m+2)+i,oo);
135 ade(N*(n+m+2)+i,(N-1)*(n+m+2)+i,0);
136 }
137 }
138 size=(N+1)*(n+m+2);
139 t=N*(n+m+2)+n+2;
140 for(int i=1;i<=m;i++)
141 {
142 int tp=st[i][N%st[i].size()];
143 if(tp!=n+1)
144 {
145 ade(N*(n+m+2)+n+2+i,N*(n+m+2)+tp,H[i]);
146 ade(N*(n+m+2)+tp,N*(n+m+2)+n+2+i,0);
147 }
148 if(tp!=n+2)
149 {
150 ade(N*(n+m+2)+tp,N*(n+m+2)+n+2+i,H[i]);
151 ade(N*(n+m+2)+n+2+i,N*(n+m+2)+tp,0);
152 }
153 }
154 popu+=Dinic();
155 if(popu<k);else break;
156 }
157 printf("%d
",N);
158 return 0;
159 }
以上是关于LuoguP2754 [CTSC1999]家园(分层图,最大流)的主要内容,如果未能解决你的问题,请参考以下文章