题目大意
给一张n个点的无向图,要求给每个点染色0或1,使得每个点的相邻相同颜色点的数量小于等于其度数的一半。
解题分析
没想到什么好的算法,就随机乱搞了。
若某个状态时,一个点的度数为cnt,相邻相同颜色点的数量为x。
定义delta = cnt / 2 - x;
若delta>=0,说明这是一个合法的状态,则接受它。若delta<0,说明这是一个不合法的状态,以exp(delta/T)的概率接受它。
当T越低时,exp(delta/T)的值越小,接受这个不合法的状态的概率则越小。
ps:参数的设置好谜啊。感觉根本不是在模拟退火,而是在瞎搞。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 1008 19 #define M 2000008 20 #define eps 1e-8 21 #define LL long long 22 #define lson l,m,rt<<1 23 #define rson m+1,r,rt<<1|1 24 #define clr(x,v) memset(x,v,sizeof(x)); 25 #define bitcnt(x) __builtin_popcount(x) 26 #define rep(x,y,z) for (int x=y;x<=z;x++) 27 #define repd(x,y,z) for (int x=y;x>=z;x--) 28 const int mo = 1000000007; 29 const int inf = 0x3f3f3f3f; 30 const int INF = 2000000000; 31 /**************************************************************************/ 32 int n; 33 int c[N]; 34 vector <int> eg[N]; 35 double rd(){ 36 return rand() % 10000 / 10000.0; 37 } 38 int main(){ 39 srand(time(NULL)); 40 scanf("%d",&n); 41 for (int u=0;u<n;u++){ 42 int num; 43 scanf("%d:",&num); 44 for (int i=1;i<=num;i++){ 45 int v;scanf("%d",&v); 46 eg[u+1].push_back(v+1); 47 } 48 } 49 clr(c,0); 50 int pp=0; 51 double T=1000,r=0.999; 52 while (T > eps){ 53 pp++; 54 int u = rand() % n + 1; 55 int cnt=0,num=0; 56 for (int i=0;i<eg[u].size();i++){ 57 int v=eg[u][i]; 58 cnt++; 59 if (c[u]==c[v]) num++; 60 } 61 int delta=cnt/2-num; 62 if (delta<0 && rd() > exp(delta/T)){ 63 c[u]^=1; 64 } 65 T = T * r; 66 } 67 printf("%d ",n ); 68 for (int i=1;i<=n;i++){ 69 printf("%d %d:",c[i],eg[i].size()); 70 for (int j=0;j<eg[i].size();j++) printf(" %d",eg[i][j]-1); 71 printf(" "); 72 } 73 }