专项测试 图论2


T1 收藏家

n个人,m条边,每个人可以把东西传给有直接连边的人,按时间顺序进行,求1最后的最大种类数

最大流

每个人拆成m+1人

s向0时刻每个人连容量为1的边,每个人向下一时刻连容量为a[i]的边

最后时刻的1向t连容量为a[1]的边

不必拆成m个,可以只在x出现的时刻新建x

T2 旅行

设f[i]表示 i 点最大期望步数

若使f[u]最大,且u->v,那么f[v]也要保证最大,需要在拓扑序上求f

有两个限制,(x,y)删y后x也得删,且x,y同起点

当计算f[u]时

\[f_u=1+\frac{\sum_{u->v没删}f_v}{\sum_{u->v没删}1} \]

01分数规划,二分答案,设剩下了k条边

\[\sum_{u->v没删}1+f_v>k* mid \]

第一个限制转化一下就是,(x,y)x存在,那y也一定存在

然后就是最大权闭合子图

代码

T1

#include
#include
#include
#include
using namespace std;
#define il inline
const int N=3e3+11;
const int inf=0x7fffffff;
struct qxxx{int v,next,w;}cc[20*N];
int n,m,s,t,tot;
int last[N];
int a[N],d[N*20];
int first[N*20],now[N*20],cnt=1;
int tim[N][N];
queue dui;
il int min_(int x,int y){return x>y?y:x;}
il void qxx(int u,int v,int w){cc[++cnt]={v,first[u],w};first[u]=cnt;return;}
il void add(int u,int v,int w){qxx(u,v,w),qxx(v,u,0);/*cout<'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
bool bfs()
{
	while(dui.size())dui.pop();
	memset(d,0,sizeof(d));
	d[s]=1;
	now[s]=first[s];
	int x;
	dui.push(s);
	while(dui.size())
	{
		x=dui.front();
		dui.pop();
		for(int i=first[x];i;i=cc[i].next)
			if(cc[i].w&&!d[cc[i].v])
			{
				d[cc[i].v]=d[x]+1;
				now[cc[i].v]=first[cc[i].v];
				dui.push(cc[i].v);
				if(cc[i].v==t) return 1;
			}
	}
	return 0;
}
int dinic(int x,int flow)
{
	if(x==t) return flow;
	int rest=flow,i,k;
	for(i=now[x];i;i=now[x]=cc[i].next)
	{
		if(cc[i].w&&d[cc[i].v]==d[x]+1)
		{
			k=dinic(cc[i].v,min_(rest,cc[i].w));
			if(!k) d[cc[i].v]=0;
			rest-=k;
			cc[i].w-=k;
			cc[i^1].w+=k;
		}
		if(!rest) break;
	}
	return flow-rest;
}
void init()
{
	memset(cc,0,sizeof(cc));
	memset(first,0,sizeof(first));
	memset(last,0,sizeof(last));
	memset(tim,0,sizeof(tim));
	cnt=1;
	return;
}
void solve()
{
	int h=read();
	while(h--)
	{
		init();
		n=read();
		m=read();
		t=n+3*m+1;
		s=0;
		for(int i=1;i<=n;++i) a[i]=read(),tim[i][0]=i,add(s,i,1),last[i]=i;
		tot=n;
		for(int x,y,i=1;i<=m;++i)
		{
			x=read(),y=read();
			tim[x][i]=++tot;
			tim[y][i]=++tot;
			add(last[x],tim[x][i],a[x]);
			add(last[y],tim[y][i],a[y]);
			qxx(tim[x][i],tim[y][i],1);
			qxx(tim[y][i],tim[x][i],1);
//			cout<

T2

#include
using namespace std;
#define il inline
const int N=4e4+11;
const int inf=1e9;
const double eps=1e-4;
struct qxxx{int v,next;double w;}cc[N];
struct lim_{int x,y;}ed[N];
int n,m,k,s,t;
int d[N];
int rle[N];
int cd[N];
int first[N],cnt=1,now[N];
double f[N];
vector rd[N],cb[N];
vector lim[N];
il double min_(double x,double y){return x>y?y:x;}
il void qxx(int u,int v,double w){cc[++cnt]={v,first[u],w};first[u]=cnt;return;}
il void add(int u,int v,double w){qxx(u,v,w),qxx(v,u,0);return;}
il bool jud(double x){return x>eps;}
queue tp,dui;
il int read()
{
	int s=0;
	char ch=getchar();
	while(ch>'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s;
}
bool bfs()
{
	while(dui.size()) dui.pop();
	memset(d,0,sizeof(d));
	d[s]=1,now[s]=first[s];
	int x;
	dui.push(s);
	while(dui.size())
	{
		x=dui.front(),dui.pop();
		for(int i=first[x];i;i=cc[i].next)
			if(jud(cc[i].w)&&!d[cc[i].v])
			{
				d[cc[i].v]=d[x]+1;
				now[cc[i].v]=first[cc[i].v];
				if(cc[i].v==t) return 1;
				dui.push(cc[i].v);
			}
	}
	return 0;
}
double dinic(int x,double flow)
{
	if(x==t) return flow;
	int i;
	double rest=flow,k;
	for(i=now[x];i;i=now[x]=cc[i].next)
	{
		if(jud(cc[i].w)&&d[cc[i].v]==d[x]+1)
		{
			k=dinic(cc[i].v,min_(rest,cc[i].w));
			if(!jud(k)) d[cc[i].v]=0;
			rest-=k;
			cc[i].w-=k;
			cc[i^1].w+=k;
		}
		if(!jud(rest)) break;
	}
	return flow-rest;
}
void init()
{
	memset(first,0,sizeof(first));
	memset(cc,0,sizeof(cc));
	cnt=1,s=t=0;
	return;
}
bool check(int x,double mid)
{
	init();
	s=0,t=cb[x].size()+1;
	double maxflow=0,flow,sum=0,val=0;
	for(int v,i=0;ieps) add(s,rle[v],val),sum+=val;
		else add(rle[v],t,-val);
	}
	for(int u,v,i=0;ieps;
}
void solve(int x)
{
	for(int i=0;i