首页 > 其他分享 >题解:P5786 [CQOI2008] 传感器网络

题解:P5786 [CQOI2008] 传感器网络

时间:2024-06-11 19:57:10浏览次数:9  
标签:head P5786 val int 题解 tot dep CQOI2008 push

题意

从一个 \(n\) 个结点的有向无环图里选出 \(n-1\) 条边,构成一棵树,且 除根节点以外的 点的儿子个数的最大值最小。

输出满足题意的节点的父亲,要求字典序最小。

思路

我们肯定要先把最小值求出来。

很容易看出是 拆点 + 二分答案求解,这里要注意的是拆完的两个点是不用连起来的,将做为儿子的点与源点连边,权值为 \(1\) 来限制;作为父亲的点依据二分的值与汇点连边,剩下的边输入边连就行。


然后就是 \(O(n^2)\) 的枚举来确定答案 蒟蒻不会二分验证

从 \(1\) 开始遍历每一个点,先将之前连向可能父节点的边清空,再从小到大附上值并跑一遍最大流,如果可以就证明有解

注意

这道题要保证字典序最小,而控制中心用 \(n\) 表示,所以能连向控制中心的也可以连其他的

代码

剩下要注意的就看代码吧,写了注释

我好像是写的最麻烦的那个

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,inf=1e9;
int n,m,s,t,tot=1,ans,_,fa[N];
int head[N],nxt[N],to[N],val[N];
int dep[N],cur[N],g[N],gg[N],fl[N];
//_,g,gg 分别用于暂存 tot,val,head方便回溯 
vector<int>v[N],mp[N];
//Dinic 板子 
inline void add(int u,int v,int w)
{
	nxt[++tot]=head[u];
	head[u]=tot;
	to[tot]=v;
	val[tot]=w;
	return ;
}
inline void insert(int u,int v,int w)
{
	add(u,v,w);
	add(v,u,0);
	return ;
}
inline bool bfs()
{
	for(int i=1;i<=t;i++)
		dep[i]=0;
	queue<int>q;
	q.push(s);
	dep[s]=1;
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		cur[x]=head[x];
		for(int i=head[x],y;i;i=nxt[i])
		{
			y=to[i];
			if(val[i]&&!dep[y])
			{
				dep[y]=dep[x]+1;
				q.push(y);
			}
		}
	}
	return dep[t];
}
inline int dfs(int x,int flow)
{
	if(x==t)
		return flow;
	int res=flow;
	for(int i=cur[x],y,k;i&&res;i=nxt[i])
	{
		y=to[i];
		cur[x]=i;
		if(val[i]&&dep[y]==dep[x]+1)
		{
			k=dfs(y,min(res,val[i]));
			val[i]-=k;
			val[i^1]+=k;
			res-=k;
		}
	}
	return flow-res;
}
//暂存 
inline void init()
{
	for(int i=1;i<=tot;i++)
		g[i]=val[i];
	for(int i=1;i<=t;i++)
		gg[i]=head[i];
	_=tot;
	return ;
}
//回溯 
inline void tini()
{
	for(int i=1;i<=tot;i++)
		val[i]=g[i];
	for(int i=1;i<=t;i++)
		head[i]=gg[i];
	tot=_;
	return ;
}
int main()
{
	cin>>n;
	s=2*n+1;
	t=2*n+2;
	char ch;
	for(int i=1;i<=n;i++)
	{
		insert(s,i,1);
		cin>>ch;
		if(ch=='Y')
		{
			insert(i,t,1); //这里向汇点连边的时候也要存进 vector 里!!! 
			v[i].push_back(t);
			mp[i].push_back(tot-1);
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			cin>>ch;
			if(ch=='Y')
			{
				insert(i,n+j,1);
				v[i].push_back(j);
				mp[i].push_back(tot-1);
			}
		}
	for(int i=1;i<=n;i++) //写的好唐,其实不用这样的 
		sort(v[i].begin(),v[i].end());
	init();
	int l=0,r=1000,mid,res;
	while(l<=r) // 二分求最小值 
	{
		mid=l+r>>1;
		for(int i=1;i<=n;i++)
			insert(n+i,t,mid);
		ans=0;
		while(bfs())
			ans+=dfs(s,inf);
		tini();
		if(ans==n)
		{
			r=mid-1;
			res=mid;
		}
		else
			l=mid+1;
	}
	for(int i=1;i<=n;i++)
		insert(n+i,t,res);
	for(int i=1;i<=n;i++)
	{
		for(auto it : mp[i])
			val[it]=0; //清空所有向可能父亲的连边 
		init();
		for(auto it : v[i])
		{
			int j=it==t?n+2:it;
			insert(i,n+j,1);
			ans=0;
			while(bfs())
				ans+=dfs(s,inf);
			tini();
			if(ans==n) //确定答案后把边加进去 
			{
				fa[i]=j;
				insert(i,n+j,1);
				init();
				break;
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(fa[i]==n+2) // 写的唐了,也不用这么写的 
			fa[i]--;
		printf("%d ",fa[i]-1);
	}
	return 0;
}

附带数据生成器

标签:head,P5786,val,int,题解,tot,dep,CQOI2008,push
From: https://www.cnblogs.com/lxyt-415x/p/18242613/The-Second

相关文章

  • 2024年新高考2卷精选试题解答
    **(2024年新高考2卷19题)**已知双曲线$C:x^2-y^2=m\(m>0)$,点$P_1(5,4)$在$C$上,$k$为常数,$0<k<1$.按照如下方式依次构造点$P_n\\left(n=2,3,\cdots\right)$:过$P_{n-1}$作斜率为$k$的直线与$C$的左支交于点$Q_{n-1}$,令$P_n$为$Q_{n-1}$关于$y$轴的对称点,记$P_{n}$的坐标......
  • AT_hitachi2020_c ThREE 题解
    题意:给定一颗树,构造一个排列\(p\)使得对于每一对\((x,y),dis(x,y)=3\),有\(3\midp_x+p_y\)或\(3\midp_x\timesp_y\)。首先我们先将所有\(p_i\)都模上\(3\)。条件等价于每一对距离为\(3\)的\((x,y)\),\(p_x\)和\(p_y\)不同时为\(1\)或\(2\)。那先考虑如......
  • 嵌入式开发常见问题解决方法
    一、问题复现稳定复现问题才能正确的对问题进行定位、解决以及验证。一般来说,越容易复现的问题越容易解决。1.1模拟复现条件有的问题存在于特定的条件下,只需要模拟出现问题的条件即可复现。对于依赖外部输入的条件,如果条件比较复杂难以模拟可以考虑程序里预设直接进入对应......
  • Windows共享文件夹常见问题解决方法
    目录你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问允许自己电脑去访问局域网其他电脑的共享文件允许局域网内别人电脑访问自己电脑的共享文件你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问参考:https://blog.csdn.net/qq28574......
  • 启动应用程序出现efsui.exe找不到问题解决
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个efsui.exe文件(挑选合适的版本文件)把它放入......
  • 启动应用程序出现findstr.exe找不到问题解决
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个findstr.exe文件(挑选合适的版本文件)把它放......
  • CF297C Splitting the Uniqueness 题解
    CF297CSplittingtheUniqueness题解非常好构造题,使我的草稿纸旋转。解法我们记输入的数组为aaa,需要输出的两个数组为b......
  • Atcoder357D题解(求解等比数列求和公式的推导)
    解题思路设连接之后的N等于Nlast,w=10^(N在10进制下的长度,例如N=5,那么w=10)Nlast=N+N*w+N*(w^2)+N*(w^3)+.....+N*(w^n)举个例子N=5,因为510进制的长度是1,所以w=10,那么Nlast=5+5*10(w)^1+5*10(w)^2+5*10(w)^3+......
  • Luogu P1784 数独 [ 模板 ] / P1074 靶形数独 题解 [ 蓝 ] [ 深搜 ] [ 剪枝 ] [ 卡常
    数独模板,靶形数独卡了2h,再也不想写数独了。思路显然是对每个格子进行枚举,类似八皇后的方法去做,朴素方法是由\((1,1)\)到\((9,9)\)遍历过去。优化我们人在做数独时,会优先选择已填格数多的行、列、区域,这样可以保证尝试次数少。同样,这一点在本题中也可以应用,但是有两......
  • [题解]P9432 [NAPC-#1] rStage5 - Hard Conveyors
    P9432[NAPC-#1]rStage5-HardConveyors题意简述给定一个\(N\)个节点的树形结构,其中有\(k\)个关键节点。接下来有\(q\)次询问,每次询问给定\(x,y\),请输出\(x\)到\(y\)至少经过一个关键点的最短路径。解题思路我们发现,这道题相当于让我们从\(x\)到\(y\)的简单路径上,额外扩展......