CF350E Wrong Floyd

发布时间 2023-10-18 20:32:25作者: 空気力学の詩

什么一眼构造题

首先要卡Floyd的关键就是存在某两个点\(x,y\),满足这两个点之间的所有最短路经过的点中(除\(x,y\)本身)至少有一个非关键点

因此很容易想到如下构造法,先随便找一个关键点\(K\),然后把所有非关键点和\(K\)连边(当然如果所有点都是关键点就显然无解)

接下来先随便连边保证图连通(刚开始没看到这条,以为方法假了),然后再随便连边把边数卡到\(m\)条即可

注意在任何时候都不能让\(K\)和其它点连边,然后算一下这样构造的边数上界为\(\frac{(n-1)\times (n-2)}{2}+n-k\),当\(m\)超过这个值是就无解

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=305;
int n,m,k,a[N],vis[N],ext[N],G[N][N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j; for (scanf("%d%d%d",&n,&m,&k),i=1;i<=k;++i) scanf("%d",&a[i]),vis[a[i]]=1;
	if (k==n||1LL*(n-1)*(n-2)/2LL+n-k<m) return puts("-1"),0;
	int pos; for (ext[a[1]]=i=1;i<=n;++i)
	if (!vis[i]) printf("%d %d\n",a[1],i),G[a[1]][i]=G[i][a[1]]=ext[i]=1,--m,pos=i;
	for (i=1;i<=n;++i) if (!ext[i])
	printf("%d %d\n",pos,i),G[pos][i]=G[i][pos]=1,--m;
	for (i=1;i<=n&&m;++i) if (i!=a[1])
	for (j=i+1;j<=n&&m;++j) if (j!=a[1])
	if (!G[i][j]) printf("%d %d\n",i,j),G[i][j]=G[j][i]=1,--m;
	return 0;
}