C/C++教程

洛谷 P4298 [CTSC2008]祭祀 题解--zhengjun

本文主要是介绍洛谷 P4298 [CTSC2008]祭祀 题解--zhengjun,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

思路

第一问

第一问与YbtOJ「图论」第1章 二分图匹配 J. 祭祀一模一样。

考虑处理出原 dag 图的两两点之间能否可达(可用 Floyd),然后题中是求最大的若干点之间没有两两可达的点对。

那么建出二分图之后,发现如果出现一对匹配,那么相当于这两个点里面有一个不能选了,所以答案就是总的点数-最大匹配。

第三问(第二问基于第三问处理)

对于每个点,如果已经选了这个点,那么这个点能到达的点以及能到达这个点的点都不能选,直接扔掉不放到二分图中。

然后用剩下的点建出二分图跑一边答案,如果现在答案=原来答案-1,那么这个点就是可以作为答案的。

第二问

直接从前往后枚举所有点,如果当前点是可以作为答案的,那么直接选进答案里来。

然后在把这个点能到达的点以及能到达这个点的点打个标记不要选就行了。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=2e2+10,M=N*N;
int n,m,s,t,head[N],kk,is[N][N],d[N],cur[N],flag[N],ans,able[N],tag[N];struct edges{int to,c,nex;}edge[M];
void add(int u,int v,int c){edge[++kk]={v,c,head[u]};head[u]=kk;edge[++kk]={u,0,head[v]};head[v]=kk;}
bool bfs(){
	queue<int>q;q.push(s);memset(d,-1,sizeof d);d[s]=0;cur[s]=head[s];for(int u;!q.empty();q.pop()){
		u=q.front();for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex)
			if(!~d[v]&&edge[i].c)q.push(v),d[v]=d[u]+1,cur[v]=head[v];
	}return ~d[t];
}
int dfs(int u,int lim=1e9){
	if(u==t)return lim;int flow=0;for(int i=head[u],v;v=edge[i].to,i&&flow<lim;i=edge[i].nex){
		cur[u]=i;if(d[v]!=d[u]+1||!edge[i].c)continue;int f=dfs(v,min(lim-flow,edge[i].c));
		if(!f)d[v]=-1;edge[i].c-=f;edge[i^1].c+=f;flow+=f;
	}return flow;
}
int dinic(){int maxflow=0;while(bfs())maxflow+=dfs(s);return maxflow;}
void clear(){memset(head,0,sizeof head);memset(flag,0,sizeof flag);kk=1;}
int main(){
	scanf("%d%d",&n,&m);for(int i=1,u,v;i<=m;i++)scanf("%d%d",&u,&v),is[u][v]=1;s=0;t=n+n+1;
	for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)is[i][j]|=is[i][k]&is[k][j];
	clear();for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(is[i][j])add(i,j+n,1);
	for(int i=1;i<=n;i++)add(s,i,1),add(i+n,t,1);printf("%d\n",ans=n-dinic());for(int u=1,cnt;cnt=n,u<=n;u++){
		clear();for(int i=1;i<=n;i++)if(is[i][u]||is[u][i]||u==i)cnt--,flag[i]=1;
		for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(is[i][j]&&!flag[i]&&!flag[j])add(i,j+n,1);
		for(int i=1;i<=n;i++)add(s,i,1),add(i+n,t,1);able[u]=cnt-dinic()==ans-1;
	}clear();for(int i=1;i<=n;i++)if(able[i]&&!flag[i]){tag[i]=1;for(int j=1;j<=n;j++)if(is[i][j]||is[j][i]||i==j)flag[j]=1;}
	for(int i=1;i<=n;i++)putchar(tag[i]+'0');puts("");for(int i=1;i<=n;i++)putchar(able[i]+'0');return 0;
}
这篇关于洛谷 P4298 [CTSC2008]祭祀 题解--zhengjun的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!