滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
这个题有两种思路,1是求带下界的最小流,2是求带下界的最小费用流。。。。。。
好板。
AC Code:(思路二)
#include<bits/stdc++.h>
#define maxn 205
#define maxm maxn * maxn
#define inf 0x3f3f3f3f
using namespace std;
int n,S,T,SS,TT,pcap[maxn];
int buf[maxn],info[maxn],Prev[maxm],to[maxm],cap[maxm],cst[maxm],cnt_e=1;
void Node(int u,int v,int c,int ct){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=ct,cap[cnt_e]=c; }
void Line(int u,int v,int c,int ct){ Node(u,v,c,ct),Node(v,u,0,-ct); }
int dis[maxn];
bool vis[maxn];
int cost = 0;
int aug(int now,int Max,int S,int T)
{
if(now == T){ cost += dis[S] * Max; return Max; }
int inc , st = Max;
vis[now] = 1;
for(int &i=info[now];i;i=Prev[i])
{
if(cap[i] && dis[to[i]] + cst[i] == dis[now] && !vis[to[i]])
{
inc = aug(to[i] , min(cap[i] , st) , S , T);
st -= inc , cap[i] -= inc , cap[i^1] += inc;
if(!st) break;
}
}
vis[now] = 0;
return Max - st;
}
bool SPFA(int S,int T)
{
static queue<int>q;
static bool inq[maxn];
memset(dis,0x3f,sizeof dis);
q.push(T),dis[T] = 0;
for(int now;!q.empty();)
{
now = q.front() , q.pop() , inq[now] = 0;
for(int i=info[now];i;i=Prev[i])
if(cap[i^1] && dis[to[i]] > dis[now] + cst[i^1])
{
dis[to[i]] = dis[now] + cst[i^1];
if(!inq[to[i]])
inq[to[i]] = 1 , q.push(to[i]);
}
}
return dis[S] != dis[0];
}
int MCMF(int S,int T)
{
cost = 0;
memcpy(buf,info,sizeof info);
int stm = 0;
for(;SPFA(S,T);)
{
stm += aug(S,inf,S,T),
memcpy(info,buf,sizeof buf);
}
return cost;
}
int main()
{
scanf("%d",&n);
S = n + 1 , T = n + 2 , SS = n+3 , TT = n+4;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
while(x--)
{
int v;
scanf("%d",&v);
Line(i,v,inf,0);
pcap[i] -- , pcap[v]++;
}
Line(S,i,inf,0);
Line(i,T,inf,0);
}
Line(T,S,inf,1);
for(int i=1;i<=n;i++)
if(pcap[i] > 0)
Line(SS,i,pcap[i],0);
else
if(pcap[i] < 0)
Line(i,TT,-pcap[i],0);
printf("%d\n",MCMF(SS,TT));
}