Gym 100818G (模拟退火)

题目大意

  给一张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",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("\n");
72     }
73 }
View Code

 

posted @ 2016-08-25 15:13  rpSebastian  阅读(199)  评论(0)    收藏  举报