题目链接:点我传送
算法初步:点我传送
算法证明:我不会且找不到
=====回归正题=====
首先大家一眼就看出来这道问题的实质:给你一个无向图,用最少的颜色染色,使得相连接的两个点颜色不同。
(不要告诉我有板子。
这种题目就要用到一种恒牛掰的算法=======最大势算法!!!
(第一反应==这什么鬼
(第二反应==百度
百度的童鞋萌,泥萌走出了正确的一步!!!
算法的主要思想是这样的:开始时每个点标记为零。
之后每次找剩下的元素中标记最大的点,删除,并且与这个点连接的点标记加一(已被删除的点标记不变)。
重复上一行直到所有元素被删除,所有点标记的种类数既是答案。
=====算法图示====
以该题样例为例。
开始时:标记全部为0.
①删除==之后(②④标记++)
②标记一个,最大之一,删除(③④++,①已被删除,标记不变)
④标记大于③,④删除③标记++
最后把③删除。
1--4共有0.1.2.2个标记,有0.1.2三种,输出3。
=====算法实现&优化=====点我传送=三楼正解
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <windows.h>
#define rep(j,k,l) for (int j=k;j<=l;j++)
using namespace std;
int ne[2222222],to[2222222],st[11111],used[11111];
int stt[11111],too[6666666],next[6666666],lych[11111],du[11111];
int n,m;
void add(int k,int l,int i){
to[i]=l;
ne[i]=st[k];
st[k]=i;
}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,m){
int k,l;
scanf("%d%d",&k,&l);
add(k,l,i*2-1);
add(l,k,i*2);
}
memset(used,0,sizeof(used));
rep(i,1,n) next[i]=i-1,too[i]=i;
stt[0]=n;
int num=0,best=0,mm=n;
while (num!=n){
if (stt[best]==0){
best--;continue;
}
if (used[too[stt[best]]]==0){
int x=too[stt[best]];
used[too[stt[best]]]=1;
stt[best]=next[stt[best]];
lych[du[x]]=1;
num++;
best=best<=du[x]?du[x]:best;
//printf("%d\n",x);
for (int i=st[x];i!=0;i=ne[i]){
if (used[to[i]]==0){
du[to[i]]++;
//printf("%d %d\n",to[i],du[to[i]]);
//printf("%d %d\n",du[to[i]],best);
next[++mm]=stt[du[to[i]]];
too[mm]=to[i];
stt[du[to[i]]]=mm;
lych[du[to[i]]]=1;
best=best<=du[to[i]]?du[to[i]]:best;
//printf("%d233\n",best);
//printf("%d\n",ne[i]);
}
}
}
else stt[best]=next[stt[best]];
}
//rep(i,1,mm) printf("%d %d\n",to[i],ne[i]);
//rep(i,1,n) printf("%d\n",st[i]);
int aaa=0;
rep(i,0,n) aaa+=lych[i];//printf("%d %d\n",i,lych[i]);
printf("%d\n",aaa);
system("pause");
return 0;
}