2018-3-22模拟考试 法师

Posted on 2018-03-28 22:50  SirKnight  阅读(97)  评论(0)    收藏  举报

根据时间向图中加边,将每个点都拆成每一天时的情况,当天可以向下一天滞留无限的人,每一天的起点和终点都分别与源汇连容量为正无穷的边,当最大流大于等于人数时就输出,无解用并查集维护即可。当前弧优化真的快好多。

#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;

const int maxn=5001,inf=2147483647;
int fa[15],h[501],r[501],a[9000][4],first[maxn],cur[maxn],nxt[maxn*100],to[maxn*100],w[maxn*100],dis[maxn];
int n,m,k,tot=0,s=4999,t=5000,cnt=0,flow=0;

int read()
{
	char ch=getchar();
	int flag=1,x=0;
	while((ch<'0'||ch>'9')&&ch!='-')
		ch=getchar();
	if(ch=='-')
	{
		flag=-1;
		ch=getchar(); 
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*flag;
}

int find(int x)
{
	if(x==fa[x])
		return x;
	return fa[x]=find(fa[x]);	
}

void add(int x,int y,int wi)
{
	nxt[cnt]=first[x];
	first[x]=cnt;
	to[cnt]=y;
	w[cnt]=wi;
	cnt++;
}

bool bfs()
{
	memset(dis,0x3f,sizeof(dis));
	queue<int>q;
	dis[s]=0;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		int i;
		for(i=first[u];i!=-1;i=nxt[i])
		{
			if(w[i]&&dis[u]+1<dis[to[i]])
			{
				dis[to[i]]=dis[u]+1;
				q.push(to[i]);
			}
		}
	}
	if(dis[t]==dis[4998])
		return 0;
	return 1;
}

int dfs(int x,int flow)
{
	if(x==t)
		return flow;
	for(int &i=cur[x];i!=-1;i=nxt[i])
	{
		if(w[i]&&dis[to[i]]==dis[x]+1)
		{
			int temp=dfs(to[i],(int)min(flow,w[i]));
			if(temp)
			{
				w[i]-=temp;
				w[i^1]+=temp;
				return temp;
			}
		}
	}
	return 0;
} 

int dinic(int x)
{
	int i;
	for(i=0;i<=14;i++)
	{
		add(x*15+i,(x+1)*15+i,inf);
		add((x+1)*15+i,x*15+i,0);
	}
	for(i=1;i<=tot;i++)
	{
		if(a[i][3]==x%r[a[i][2]])
		{
			add(x*15+a[i][0],(x+1)*15+a[i][1],h[a[i][2]]);
			add((x+1)*15+a[i][1],x*15+a[i][0],0);
		}
	}
	add(s,x*15,inf);
	add(x*15,s,0);
	add(x*15+14,t,inf);
	add(t,x*15+14,0);
	while(bfs())
	{
		for(i=0;i<=5000;i++)
			cur[i]=first[i];
		int temp;
		while(temp=dfs(s,inf))
			flow+=temp; 
	}
	return flow;//总共 
}

int main()
{
	memset(first,-1,sizeof(first));
	n=read(),m=read(),k=read();
	int i;
	for(i=0;i<=14;i++)
		fa[i]=i;
	for(i=1;i<=m;i++)
	{
		h[i]=read(),r[i]=read();
		int j,la,lat,now;
		for(j=0;j<r[i];j++)
		{
			if(j==0)
			{
				la=read();
				if(la==-1)
					la=14;
				lat=la;
			}
			else
			{
				now=read();
				if(now==-1)
					now=14;
				int fx=find(la),fy=find(now);
				if(fx!=fy)
					fa[fy]=fx;
				a[++tot][0]=la,a[tot][1]=now,a[tot][2]=i,a[tot][3]=j-1;
				la=now;
				if(j==r[i]-1)
					a[++tot][0]=now,a[tot][1]=lat,a[tot][2]=i,a[tot][3]=j;
			}
		}
	}
	int fx=find(0),fy=find(14);
	if(fx!=fy)
	{
		printf("somebodysetupusthebomb\n");
		fclose(stdin);
		fclose(stdout);
		return 0;
	}
	int ans=0;
	while(true)
	{
		if(dinic(ans)>=k)
		{
			printf("%d\n",ans);
			break;
		}
		ans++;
	}
	return 0;
}