版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目描述
一个国家有n个城市,城市之间连接着双向航空线路。一位疯狂的航空公司总裁Ronald Krump经常改变航班时刻表。更准确地说,他每天都做以下事情:
●选择其中一个城市
●如果该城市和某个其他城市之间之前没有航线那么在这两个城市之间创建一条航线,如果该城市和某个其他城市之间之前已有航线那么取消这条航线
例如,如果从城市5有航线通往城市1和2,但没有航线通往城市3和4,那么在Krump选择城市5并进行操作后,将有从城市5通往城市3和4的航线,但没有从城市5通往城市1和2的航线。
这个国家的公民在想,是否有一天航线图会变为完全图。换言之,当天任意两个不同的城市之间存在一条航线(直达)。写一个程序,根据当前的航线图,确定是否有可能有某一天出现这种情况,通过Krump的操作。
输入格式
第一行输入包含一个整数N(2≤N≤1000)。表示城市的数量。城市从1到N编号。 第二行输入包含一个整数M(0≤M≤N*(N-1)/2)。表示当前航线的数量。 接下来M行每行包含两个不同的整数,表示一条航线连接的两个城市的编号。
输出格式
如果有一天航线图会变为完全图,那么输出“DA”。否则输出“NE”。输出均不含引号。
样例
样例输入1
2 0
样例输出1
DA
样例输入2
3 2 1 2 2 3
样例输出2
NE
样例输入3
4 2 1 3 2 4
样例输出3
DA
思路详解
题中没有重边,因为官方题解说 “从题意我们分析不可能有重边,因为两个城市间开两条航线浪费空中资源” (好TM牵强)
我们知道完全图有 n*(n-1)/ 2 条边,然后就开始暴力的搜索每一个点寻找完全子图,在子图添上 完全子图的点数 * 剩下的点数条边就构成一个完全图(自己手推一下),不难理解,所以在原来边数+完全子图的点数 * 剩下的点数=n*(n-1)/ 2
就这样了,话说这总裁Ronald Krump有点sao啊
代码
理解消化。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define N 1005
using namespace std;
int n , m , sum , sumE ;
bool visE[N*N/2] , vis[N] , flag[N] ;
struct node {
int to , num ;
node () {}
node ( int To , int Num ) {
to = To , num = Num ;
}
};
vector <node> G[N] ;
void DFS( int x ) {//遍历
if( !vis[x] )
sum ++ ;//子图的点的个数
vis[x] = 1 ;
flag[x] = 1 ;//标记走过
for( int i = 0 ; i < G[x].size() ; ++ i ) {
int E = G[x][i].num , s = G[x][i].to ;
if( !visE[E] ) {
visE[E] = 1 ;
sumE ++ ;//子图的边数
DFS( s );
}
}
}
int main() {
scanf("%d%d", &n , &m );
for( int i = 1 ; i <= m ; ++ i ) {
int a , b ;
scanf("%d%d", &a , &b );
G[a].push_back( node(b,i) );
G[b].push_back( node(a,i) );
}
for( int i = 1 ; i <= n ; ++ i ) {
if( flag[i] )//不重复访问
continue ;
memset( visE , 0 , sizeof(visE) );
memset( vis , 0 , sizeof(vis) );
sum = sumE = 0 ;
DFS(i) ;
if( sum*(sum-1)/2 == sumE )//子图为完全图
break ;
}
if( n*(n-1)/2-m == sum*(n-sum) )
printf("DA");
else printf("NE");
return 0 ;
}