2019ICPC邀请赛南昌A Attack 斯坦纳树

先对8个点整体做斯坦纳树,再求出每个状态的最小代价。再看每个状态是否属于独立的,即包含的点都是成对的,我们去更新这些独立的状态即可。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <string>
  4 #include <map>
  5 #include <queue>
  6 #include <iostream>
  7 using namespace std;
  8 const int MAXN = 40,MAXM = 2100;
  9 queue <int> que;
 10 string s1,s2;
 11 map <string,int> mp;
 12 bool inq[MAXN];
 13 int head[MAXN],dis[MAXN][1 << 8],ans[1 << 8],spe[1 << 8],to[MAXM],nxt[MAXM],val[MAXM];
 14 int cnt,n,m,s,t,inf;
 15 void add(int x,int y,int v)
 16 {
 17     nxt[++cnt] = head[x];
 18     to[cnt] = y;
 19     val[cnt] = v;
 20     head[x] = cnt;
 21 }
 22 void SPFA(int o)
 23 {
 24     while(!que.empty())
 25     {
 26         int t = que.front();
 27         que.pop();
 28         inq[t] = false;
 29         for(int i = head[t];i;i = nxt[i])
 30         {
 31             if(dis[to[i]][o] > dis[t][o] + val[i])
 32             {
 33                 dis[to[i]][o] = dis[t][o] + val[i];
 34                 if(!inq[to[i]])
 35                 {
 36                     inq[to[i]] = true;
 37                     que.push(to[i]);
 38                 }
 39             }
 40         }
 41     }
 42 }
 43 void steiner_tree()
 44 {
 45     for (int i = 0;i < (1 << 8);i++)
 46     {
 47         for (int j = 1;j <= n;j++)
 48         {
 49             for (int k = i;k;k = (k - 1) & i)
 50                 dis[j][i] = min(dis[j][i],dis[j][k] + dis[j][i - k]);
 51             if (dis[j][i] != inf)
 52             {
 53                 que.push(j);
 54                 inq[j] = true;
 55             }
 56         }
 57         SPFA(i);
 58     }
 59 }
 60 bool check(int o)
 61 {
 62     for (int i = 0;i <= 7;i += 2)
 63         if (((o >> i) & 1) ^ ((o >> (i + 1)) & 1))
 64             return false;
 65     return true;
 66 }
 67 int main()
 68 {
 69     while (scanf("%d%d",&n,&m) > 0)
 70     {
 71         cnt = 0;
 72         memset(head,0,sizeof(head));
 73         memset(nxt,0,sizeof(nxt)); 
 74         memset(dis,0x1f,sizeof(dis));
 75         memset(ans,0x1f,sizeof(ans)); 
 76         inf = ans[0];
 77         int tv;
 78         string s1,s2;
 79         for (int i = 1;i <= n;i++)
 80         {
 81             cin >> s1;
 82             mp[s1] = i;
 83         }
 84         for (int i = 1;i <= m;i++)
 85         {
 86             cin >> s1 >> s2;
 87             scanf("%d",&tv);
 88             add(mp[s1],mp[s2],tv);
 89             add(mp[s2],mp[s1],tv);
 90         }
 91         for (int i = 1;i <= 8;i++)
 92         {
 93             cin >> s1;
 94             dis[mp[s1]][1 << (i - 1)] = 0;
 95         }
 96         steiner_tree();
 97         for (int i = 0;i < (1 << 8);i++)
 98         {
 99             spe[i] = check(i);
100             for (int j = 1;j <= n;j++)
101                 ans[i] = min(ans[i],dis[j][i]); 
102         }
103         for (int i = 0;i < (1 << 8);i++)
104             if (spe[i])
105                 for (int j = i;j;j = (j - 1) & i)
106                     if (spe[j] && spe[i - j])
107                         ans[i] = min(ans[i],ans[j] + ans[i - j]);
108         printf("%d\n",ans[(1 << 8) - 1]);
109     }
110     return 0;
111 }

 

posted @ 2020-03-08 10:19  IAT14  阅读(203)  评论(0编辑  收藏  举报