洛谷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\n",now+1); 149 return 0; 150 } 151 now++; 152 tot+=n1+2; 153 add+=n1+2; 154 } 155 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”