现在的位置: 首页 > 综合 > 正文

CodeForces 21D – Traveling Graph 欧拉回路的性质+状态压缩DP

2013年10月28日 ⁄ 综合 ⁄ 共 1630字 ⁄ 字号 评论关闭

      在一个无向图中..从某点出发..每个边正好经过一次可以回到自己..必要条件是所有点的度为偶数..也就在一个无向图中存在欧拉回路的必要条件...注意..是必要条件...比如说...图是不连通的...

      对应本题....题目是说从点1出发边可以经过任意多次..遍历完所有的边..回到点1的最短距离..一看N<=15...状态压缩DP..但怎么设置状态呢?...看一种特殊的情况..若是点1可以到达所有点..并且所有点的度为偶数..问题不就和欧拉回路相同么...所有边长度之和就是答案..但是题目中有度为奇数的点..就不得不多走一些路...让有些边经过不止一次..这些多走的边可以看成多加的边..比如样例2..3走回1..可以看做3到1加了一条长度为7的边...

     问题转换..最短要加多长的若干边..使得这个无向图成为一个满足欧拉回路的图...

      先用floyd找出任意两点的最短路径...作为加边的预处理...然后枚举所有的奇数度点...看怎么加边方案最优...枚举这个感觉太麻烦..不如用状态dp来做这个过程...状态k代表其为1的点度都是偶的需要加最短长度的边...由于要加边必定是加在两个度为奇的点上...所以对于一个状态..枚举其为0代表的两个奇数度点..进行更新..

Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#define ll long long
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 16
using namespace std; 
int n,sum,dp[1<<MAXN],arc[MAXN][MAXN],d[MAXN]; 
void Floyd()
{
       int k,i,j; 
       for (k=0;k<n;k++)
          for (i=0;i<n;i++)  
               for (j=0;j<n;j++)  
                  arc[i][j]=min(arc[i][j],arc[i][k]+arc[k][j]);
}
int getans()
{
       int i,j,x,t,totol;   
       Floyd(); 
       for (i=1;i<n;i++) 
          if (d[i] && arc[0][i]>oo) return -1; 
       memset(dp,0x7f,sizeof(dp)); 
       dp[0]=0;
       totol=(1<<n)-1;
       for (t=0;t<=totol;t++)
       {
             for (i=0;i<n;i++)
                if (d[i]%2 && (t & (1<<i))) break;
             if (i==n) dp[t]=0; //该状态不含奇数度点
             for (i=0;i<n;i++)
                if (d[i]%2 && !(t & (1<<i))) // 枚举奇数度点i
                   for (j=i+1;j<n;j++) 
                      if (d[j]%2 && !(t & (1<<j)) && arc[i][j]<oo) // 枚举奇数度点j
                         dp[t|(1<<i)|(1<<j)]=min(dp[t|(1<<i)|(1<<j)],dp[t]+arc[i][j]);
       }
       if (dp[totol]>oo) return -1;
       return sum+dp[totol]; 
}
int main()
{ 
       int m; 
       while (~scanf("%d%d",&n,&m))
       { 
                sum=0; 
                memset(arc,0x3f,sizeof(arc)); 
                memset(d,0,sizeof(d));
                for (int i=1;i<=m;i++)
                {
                       int x,y,l;
                       scanf("%d%d%d",&x,&y,&l);
                       sum+=l;
                       x--,y--; 
                       arc[y][x]=arc[x][y]=min(arc[x][y],l);                       
                       d[x]++,d[y]++;
                }                 
                printf("%d\n",getans());
       }
       return 0;
}

抱歉!评论已关闭.