题意:给你一个图,图满足每个点最多连两个边,不存在自环,两点之间不存在多个边。让后然你重新组合触一个新图,新图满足旧图的条件,但是不能存在旧图所拥有的边。问你新图是否存在?存在输出边,不存在输出-1。
条件:
- 每个点最多连两个边,不存在自环,两点之间不存在多个边
- 新图不能存在旧图所拥有的边
思路:因为他说了最多连两条边,那么我们把所有的点都连成环,如下图。然后随机环上的点,如果换上组成边和旧图不同的边大于等于旧图的边数,就输出边。
注意:产生随机数组,用rand()随机下标会超时,要用random_shuffle(不太清楚复杂度,应该比O(n)快)
random_shuffle:用来对一个元素序列进行重新排序(随机的)
使用:random_shuffle(起点位置,终点位置),可以用于迭代器例如vector,也可以用于数组
代码:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <map>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <time.h>
using namespace std;
const int maxn=1e5+5;
int ans[maxn];
int n,m;
map<pair<int,int>,int>mp;
int main()
{
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++)
{
int u,v;
scanf("%d%d",&u,&v);
mp[make_pair(u,v)]=1;
mp[make_pair(v,u)]=1;
}
for(int i=1; i<=n; i++)
{
mp[make_pair(i,i)]=1;
ans[i]=i;
}
int cnt=505;
while(cnt--)
{
random_shuffle(ans+1,ans+n+1);
ans[0]=ans[n];
int count1=0;
for(int i=0; i<n; i++)
{
if(mp[make_pair(ans[i],ans[i+1])]!=1)
{
count1++;
}
}
if(count1>=m)
{
int count1=0;
for(int i=0; i<n; i++)
{
if(mp[make_pair(ans[i],ans[i+1])]!=1)
{
printf("%d %d\n",ans[i],ans[i+1]);
count1++;
if(count1>=m)
return 0;
}
}
}
}
printf("-1\n");
return 0;
}
补充:
- pair的用法:make_pair()
- map里面使用pair来影射和使用结构体struct来映射:这里如果用pair来影射是不用写重构的,但是要映射结构体的话是需要重构的。(因为我原本不太习惯用pair,一开始用了结构体来代替pair,发现需要重构才能映射)
struct重构代码:
struct node
{
int u,v;
bool operator<(const node &a)const
{
if(u==a.u)
return v<a.v;
return u<a.u;
}
};
总结:随机方法也是做题的一个手段,还有学到了random_shuffle和map使用struct的重构问题(这个我之前课设好像也遇到过了,但没有太去深究,就忘了)。