计蒜客商汤挑战赛-D-白色相簿-难题-骚题

https://www.luogu.org/blog/KingSann/fou-chang-yong-di-hei-ke-ji-san-yuan-huan-post

 

 

商汤在线编程挑战赛SenseTimeAceCoderChallenge

原题做不了,因为这场比赛出了bug,出题人被骂的很惨很惨。

下面是一道类似题,原题是输出是否存在那个唯一三角形,这题是输出编号,本质是一样的题目。

这题难就难在数据范围超级超级大。

顶点数n≤200000

这里是讲解

题意:

 

在无向图中,如果三个不同的顶点之间都有边,则称他们组成了一个三角形。

在一张无向图 G 中,有且仅有一个三角形。现在你的任务是找到它。

输入格式

第一行两个数 n, mn,m,表示 G 的顶点个数和边的条数。

接下来 mm 行,每行两个数 i, ji,j 表示点 ii 和 jj 之间有一条边。题目保证没有重边和自环。

输出格式

输出一行,三个整数, i < j < ki<j<k ,表示三角形的三个顶点。

这题是第一场的D-白色相簿

#include<bits/stdc++.h>
#define test printf("***\n")
#define mlr(a) memset((a),0,sizeof((a)))
#define mmx(a) memset((a),0x3f,sizeof((a)))
#define ka getchar();getchar()
#define ka1 getchar()
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int N = 210005;
const int M = 4100005;
const int X = 999983;
const int INF = 1e9;
const double eps = 1e-8;
const int mod = 1e9+7;
struct lp{
	int u,v,nex,nexHash;
	lp(){}
	lp(int a,int b,int c):u(a),v(b),nex(c) {}
}cw[M];
int tot,flag,n,m;
int ar[4];
#define DEBUG
int aa[5005][205];
int dep[N];
int head[N],headHash[X];
int que[N];
int fa[N];
void add(int a,int b){
	cw[++tot]=lp(a,b,head[a]);
	head[a]=tot;
	int h=(a*30000+b)%999983;
	cw[tot].nexHash=headHash[h];
	headHash[h]=tot;
}
int findHash(int a,int b){
	int h=(a*30000+b)%999983;
	for(int i=headHash[h];i!=-1;i=cw[i].nexHash){
		if((a==cw[i].u)&&(b==cw[i].v)){
			return 1;
		}
	}
	return 0;
}
void algo2(){ 
	queue<int>Q;
	while(!Q.empty())Q.pop();
	for(int i=1;i<=n;++i){
		if(dep[i]==0){
			Q.push(i);
			fa[i]=i;
			dep[i]=1;
		}
		while(!Q.empty()){
			int at=Q.front();Q.pop();
			for(int i=head[at];i!=-1;i=cw[i].nex){
				int to=cw[i].v;
				if(dep[to])continue;
				dep[to]=1;
				Q.push(to);
				fa[to]=at;
			}
		}
	}
	for(int i=0;i<=tot;++i){
		if((cw[i].u!=fa[cw[i].u])&&(cw[i].v!=fa[cw[i].u])&&findHash(cw[i].v,fa[cw[i].u])){
			ar[0]=cw[i].u;ar[1]=cw[i].v;ar[2]=fa[cw[i].u];
			sort(ar,ar+3);
			cout<<ar[0]<<" "<<ar[1]<<" "<<ar[2]<<"\n";
			return;
		}
	}
}
void algo1(){
	for(int i=1;i<=m;++i){
		for(int j=0;j<=n/30;++j){
			if((aa[cw[i*2-1].u][j]&aa[cw[i*2-1].v][j])!=0){
				int s=aa[cw[i*2-1].u][j]&aa[cw[i*2-1].v][j];
				int k=0;
				while(s>0){
					s/=2;
					++k;
				}
				ar[0]=cw[i*2-1].u;ar[1]=cw[i*2-1].v;ar[2]=j*30+k-1;
				sort(ar,ar+3);
				cout<<ar[0]<<" "<<ar[1]<<" "<<ar[2]<<"\n";
				return;
			}
		}
	}
}
void init(){
	tot=-1;
	memset(head,-1,sizeof(head));
	memset(headHash,-1,sizeof(headHash));
	memset(dep,0,sizeof(dep));
	memset(aa,0,sizeof(aa));
}
int main(int argc, char const *argv[])
{
	iis;
	#ifdef DEBUG
    	freopen("D:in.in", "r", stdin);
   		freopen("D:out.out", "w", stdout);	
	#endif
	int a,b;
	while(cin>>n>>m){
		init();
		for(int i=0;i<m;++i){
			cin>>a>>b;
			add(a,b);add(b,a);
			if(n<=5000){
				int c=b/30;
				int d=b%30;
				aa[a][c]+=(1<<d);
				c=a/30;
				d=a%30;
				aa[b][c]+=(1<<d);
			}
		}
		if(n<=5000){
			algo1();
		}else{
			algo2();
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值