#dp#nssl 1478 题


分析

\(f[i]\)表示第\(i\)个是否幸存,\(dp[i][j]\)表示若第\(i\)个幸存,第\(j\)个是否必死
倒序枚举人,如果存在\(dp[i][a[x]],dp[i][b[x]]\)同时为是,为了避免矛盾,第\(i\)个必死
如果存在\(dp[i][a[x]],dp[i][b[x]]\)其中一个为是,那么另一个也为是
最后枚举两个点\(i,j\)若没有一个点\(k\)使得\(dp[i][k],dp[j][k]\)同时为是,那么\((i,j)\)幸存


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=411,M=50011;
int n,m,a[M],b[M],ans; bool f[N],dp[N][N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
signed main(){
	n=iut(),m=iut();
	for (rr int i=1;i<=m;++i) a[i]=iut(),b[i]=iut();
	for (rr int i=1;i<=n;++i){
		f[i]=dp[i][i]=1;
		for (rr int j=m;j>=1;--j){
			if (!dp[i][a[j]]&&!dp[i][b[j]]) continue;
			if (dp[i][a[j]]&&dp[i][b[j]]){f[i]=0; break;}
			dp[i][a[j]]=dp[i][b[j]]=1;
		}
	}
	for (rr int i=1;i<n;++i)
	for (rr int j=i+1;j<=n;++j)
	if (f[i]&&f[j]){
		rr int flag=1;
		for (rr int k=1;k<=n;++k)
		if (dp[i][k]&&dp[j][k]){
			flag=0; break;
		}
		if (flag) ++ans;
	}
	return !printf("%d",ans); 
}
posted @ 2020-08-14 21:35  lemondinosaur  阅读(92)  评论(0编辑  收藏  举报