洛谷P2754 [CTSC1999]家园

题目链接:https://www.luogu.org/problemnew/show/P2754

知识点:  最大流

解题思路:

  先用 (DFS) 判断是否无解。

  从时刻 (0) 开始枚举答案,从飞船此刻的位置往下一时刻的位置连边,容量为飞船的载客量,然后在上一刻的残量网络的基础上跑 (sap),将最大流累加起来,当最大流的累加和大于或等于 (k) 时,便可得出答案。

  对于同一个位置的不同时刻,要用不同的点代表,并且把他们按照时间的先后顺序连起来,容量为 (INF);对于代表地球的任一时刻的点,从源点连边指向它们,容量为 (INF);对于代表月亮的任一时刻的点,连一条指向源点的边,容量也为 (INF)。

AC代码:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int MAXN=10000;
  5 const int MAXM=10000;
  6 const int INF=0x3f3f3f3f;
  7 struct Edge{
  8     int to,Next,cap,flow;
  9 }edge[MAXM];
 10 int tol;
 11 int head[MAXN];
 12 int gap[MAXN],dep[MAXN],cur[MAXN];
 13 void init(){
 14     tol=0;
 15     memset(head,-1,sizeof(head));
 16 }
 17 void addedge(int u,int v,int w,int rw=0){
 18     edge[tol].to=v; edge[tol].cap=w; edge[tol].flow=0;
 19     edge[tol].Next=head[u]; head[u]=tol++;
 20     edge[tol].to=u; edge[tol].cap=rw; edge[tol].flow=0;
 21     edge[tol].Next=head[v]; head[v]=tol++;
 22 }
 23 int Q[MAXN];
 24 void BFS(int start,int ends){
 25     memset(dep,-1,sizeof(dep));
 26     memset(gap,0,sizeof(gap));
 27     gap[0]=1;
 28     int fronts=0,rear=0;
 29     dep[ends]=0;
 30     Q[rear++]=ends;
 31     while(fronts!=rear){
 32         int u=Q[fronts++];
 33         for(int i=head[u];i!=-1;i=edge[i].Next){
 34             int v=edge[i].to;
 35             if(dep[v]!=-1)  continue;
 36             Q[rear++]=v;
 37             dep[v]=dep[u]+1;
 38             gap[dep[v]]++;
 39         }
 40     }
 41 }
 42 int S[MAXN];
 43 int sap(int start,int ends,int N){
 44     BFS(start,ends);
 45     memcpy(cur,head,sizeof(head));
 46     int top=0;
 47     int u=start;
 48     int ans=0;
 49     while(dep[start]<N){
 50         if(u==ends){
 51             int Min=INF;
 52             int inser;
 53             for(int i=0;i<top;i++){
 54                 if(Min>edge[S[i]].cap-edge[S[i]].flow){
 55                     Min=edge[S[i]].cap-edge[S[i]].flow;
 56                     inser=i;
 57                 }
 58             }
 59             for(int i=0;i<top;i++){
 60                 edge[S[i]].flow+=Min;
 61                 edge[S[i]^1].flow-=Min;
 62             }
 63             ans+=Min;
 64             top=inser;
 65             u=edge[S[top]^1].to;
 66             continue;
 67         }
 68         bool flag=false;
 69         int v;
 70         for(int i=cur[u];i!=-1;i=edge[i].Next){
 71             v=edge[i].to;
 72             if(edge[i].cap-edge[i].flow && dep[v]+1==dep[u]){
 73                 flag=true;
 74                 cur[u]=i;
 75                 break;
 76             }
 77         }
 78         if(flag){
 79             S[top++]=cur[u];
 80             u=v;
 81             continue;
 82         }
 83         int Min=N;
 84         for(int i=head[u];i!=-1;i=edge[i].Next){
 85             if(edge[i].cap-edge[i].flow && dep[edge[i].to]<Min){
 86                 Min=dep[edge[i].to];
 87                 cur[u]=i;
 88             }
 89         }
 90         gap[dep[u]]--;
 91         if(!gap[dep[u]])    return ans;
 92         dep[u]=Min+1;
 93         gap[dep[u]]++;
 94         if(u!=start)    u=edge[S[--top]^1].to;
 95     }
 96     return ans;
 97 }
 98 
 99 int h[25],p[25];
100 int r[25][15];
101 vector<int> G[20];
102 bool viss[20];
103 void dfs(int rt,int moon){
104     viss[rt]=true;
105     if(rt==moon)    return;
106     for(int i=0;i<G[rt].size();i++){
107         int v=G[rt][i];
108         if(!viss[v]) dfs(v,moon);
109     }
110 }
111 
112 int main(){
113     int n1,m1,k1;
114     scanf("%d%d%d",&n1,&m1,&k1);
115     for(int i=0;i<m1;i++){
116         scanf("%d%d",&h[i],&p[i]);
117         for(int j=0;j<p[i];j++){
118             scanf("%d",&r[i][j]);
119             if(r[i][j]==-1)
120                 r[i][j]=n1+1;
121         }
122         for(int j=0;j<p[i];j++){
123             int u=r[i][j],v=r[i][(j+1)%p[i]];
124             G[u].push_back(v);
125         }
126     }
127     dfs(0,n1+1);
128     if(!viss[n1+1]){
129         puts("0");
130         return 0;
131     }
132     init();
133     int s=0,t=1;
134     int now=0,add=2,had=0;
135     int tot=2+(n1+2)*2;
136     addedge(s,add,INF);
137     addedge(add+n1+1,t,INF);
138     while(1){
139         for(int i=0;i<m1;i++){
140             int u=r[i][now%p[i]]+add,v=r[i][(now+1)%p[i]]+add+n1+2;
141             addedge(u,v,h[i]);
142         }
143         for(int i=0;i<n1+2;i++)
144             addedge(i+add,i+add+n1+2,INF);
145         addedge(add+n1+1+n1+2,t,INF);
146         had+=sap(s,t,tot);
147         if(had>=k1){
148             printf("%d
",now+1);
149             return 0;
150         }
151         now++;
152         tot+=n1+2;
153         add+=n1+2;
154     }
155 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
原文地址:https://www.cnblogs.com/Blogggggg/p/9320617.html