Ronald
首先从简单的问题开始思考。假如我们只有两个点,应该如何构造方案呢?显然,当两个点有连边时,我们不需要做任何事情(当然两个点各操作一次也是可以的但没有必要);而两个点没有连边时,只需要选择其中任意一个进行一次操作即可。从这里得出了一个重要的结论,由于操作同一个点两次之后会导致某些对点的连接状态变过去再变回来,相当于没有操作,所以一个点的操作次数要么是零次,要么是零次。
推而广之,对于任意的两个点,要让最后有边连接这两个点,也需要分类讨论。假如一开始这两个点有边,那么要么两个点都不操作,要么两个点都操作一次;假如一开始两个点没有边,那么这两个点中应该只有一个操作过一次,另一个没有操作。然后可以抽离出模型来,可以把操作一次的点放在一个集合,没操作的放在另一个集合;两个点一开始没有连边的话代表这两个点不在同一集合,否则说明在一个集合,根据这个关系判断是不是二分图即可(一个点只能属于一个集合对吧)。
具体实现不用那么麻烦,由于一开始第一个点和其它所有点的连边情况是已知的,所以可以强制一号点属于某个集合,这样一来所有点的集合归属就已经确定了,然后扫描后面的点看有没有矛盾就可以了。
#include<bits/stdc++.h>
//#define feyn
using namespace std;
const int N=1010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
int m,n;
bool e[N][N],a[N];
signed main(){
#ifdef feyn
freopen("in.txt","r",stdin);
#endif
read(m);read(n);int s1,s2;
while(n--){
read(s1);read(s2);
e[s1][s2]=e[s2][s1]=true;
}
for(int i=2;i<=m;i++)a[i]=e[1][i];
for(int i=2;i<m;i++){
for(int j=i+1;j<=m;j++){
if(e[i][j]==true&&a[i]!=a[j]){
printf("NE\n");return 0;
}
if(e[i][j]==false&&a[i]==a[j]){
printf("NE\n");return 0;
}
}
}
printf("DA\n");
return 0;
}
一如既往,万事胜意