bzoj 2502: 清理雪道

2502: 清理雪道

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 510   Solved: 276
[ Submit][ Status][ Discuss]

Description

        滑雪场坐落在 FJ 省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。

Input

输入文件的第一行包含一个整数 n  (2 <= n <= 100) –  代表滑雪场的地点的数量。接下来的 n 行,描述 1~n 号地点出发的斜坡,第 i 行的第一个数为 mi  (0 <= mi < n ,后面共有 mi 个整数,由空格隔开,每个整数 aij 互不相同,代表从地点 i 下降到地点 aij 的斜坡。每个地点至少有一个斜坡与之相连。

Output

 
        输出文件的第一行是一个整数 k  –  直升飞机的最少飞行次数。

Sample Input

8
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0

Sample Output

4

HINT

Source


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 120
#define M 100003
using namespace std;
int n,m,x,tot=-1;
int point[M],du[N],deep[M],cur[M],maxflow;
int next[M*2],remain[M*2],v[M*2],s,t,ss,tt;
const int inf=1e9;
void add(int x,int y,int z)
{
	tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
	tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}
bool bfs(int s,int t)
{
   for (int i=1;i<=t;i++) cur[i]=point[i];
   memset(deep,0x7f,sizeof(deep));
   deep[s]=0; 
   queue<int> p; p.push(s);
   while (!p.empty())
   {
   	int now=p.front(); p.pop();
   	for (int i=point[now];i!=-1;i=next[i])
   	if (deep[v[i]]>inf&&remain[i])
   	 deep[v[i]]=deep[now]+1,p.push(v[i]);
   }
   if (deep[t]>inf) return false;
   return true;
}
int dfs(int now,int t,int limit)
{
	if (now==t||!limit) return limit;
	int flow=0,f;
	for (int i=cur[now];i!=-1;i=next[i])
	{
		cur[now]=i;
		if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(remain[i],limit))))
		{
			limit-=f;
			flow+=f;
			remain[i]-=f;
			remain[i^1]+=f;
			if (!limit) break;
		}
	}
	return flow;
}
void dinic(int s,int t)
{
	maxflow=0;
	while (bfs(s,t))
	 maxflow+=dfs(s,t,inf);
}
int main()
{
  tot=-1;
  memset(point,-1,sizeof(point));
  memset(next,-1,sizeof(next));
  scanf("%d",&n);
  s=n+1; t=s+1; ss=t+1; tt=ss+1;
  for (int i=1;i<=n;i++)
  {
  	scanf("%d",&m);
  	for (int j=1;j<=m;j++)
  	 {
  	 	scanf("%d",&x);
  	 	du[i]--; du[x]++;
  	 	add(i,x,inf);
  	 }
  }
  for (int i=1;i<=n;i++)
  {
  	add(s,i,inf);
  	add(i,t,inf);
  	if (du[i]>0) add(ss,i,du[i]);
  	if (du[i]<0) add(i,tt,-du[i]);
  }
  dinic(ss,tt);
  add(t,s,inf);
  dinic(ss,tt);
  printf("%d\n",maxflow);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值