Codeforces Alpha Round #21 D. Traveling Graph(歐拉路,floyed,dp,好題)

D. Traveling Graph
time limit per test
0.5 second
memory limit per test
64 megabytes
input
standard input
output
standard output

You are given undirected weighted graph. Find the length of the shortest cycle which starts from the vertex 1 and passes throught all the edges at least once. Graph may contain multiply edges between a pair of vertices and loops (edges from the vertex to itself).

Input

The first line of the input contains two integers n and m (1 ≤ n ≤ 15, 0 ≤ m ≤ 2000), n is the amount of vertices, and m is the amount of edges. Following m lines contain edges as a triples x, y, w (1 ≤ x, y ≤ n, 1 ≤ w ≤ 10000), x, y are edge endpoints, and w is the edge length.

Output

Output minimal cycle length or -1 if it doesn't exists.

Examples
input
3 3
1 2 1
2 3 1
3 1 1
output
3
input
3 2
1 2 3
2 3 4
output
14


題意:

給出一個無向帶權圖,問從1號點出發,通過所有的邊至少一次,再回到1號點,需要花費的最少代價是多少。存在自環和重邊。

如果無法滿足上述要求,那麼輸出-1。


節點數n,邊數m。(1 <= n <= 15, 0 <= m <= 2000)

每條邊包含3個屬性u, v, w, u和v是邊的端點,w是通過邊的代價。(1 <= x,y <= n, 1 <= w <= 1e4)。



題解:

先跑一次Floyd求出全源最短路,如果1號點到某個點的最短路不存在那麼原圖不連通,
如果所有點的度數都是偶數,那麼存在一條歐拉回路,已經得到結果,
否則存在某些點的度數是奇數,嘗試用一些路徑連接這些點,只有路徑端點的度數奇偶性會發生變化,
可以發現度數已經是偶數的點作爲某條路徑的端點是不優的,於是考慮dp[S]表示度數是奇數的點集爲S時的最小代價,
轉移枚舉選出兩個集合內的點,用一條路連起來,這兩個點的度數都會變成偶數,複雜度是O(n^2*2^n),
一個trick是由於最後所有點度數都要是偶數,也就是每個度數是奇數的點都要作爲某條路徑的端點,
那麼每次考慮選出集合內標號最小的點,枚舉這個點和另一個點用一條路徑連起來,複雜度是O(n*2^n)。




#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=18;
int g[maxn][maxn],d[1<<maxn];
int deg[maxn];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i,0,n) rep(j,0,n) g[i][j]=inf;
    rep(i,0,n) g[i][i]=0;
    int sum=0;
    while(m--)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        u--,v--;
        g[u][v]=min(g[u][v],w);
        g[v][u]=min(g[v][u],w);
        deg[u]++,deg[v]++;
        sum+=w;
    }
    rep(k,0,n) rep(i,0,n) rep(j,0,n) g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    rep(i,1,n) if(deg[i]&&g[0][i]==inf) return 0*puts("-1");
    int now=0;
    rep(i,0,n) if(deg[i]&1) now|=(1<<i);
    memset(d,0x3f,sizeof(d));
    d[now]=0;
    for(int j=now;j>0;j--)
    {
        for(int i=0;i<n;i++)
        {
            if(j&(1<<i))
            {
                for(int k=i+1;k<n;k++)
                    if(j&(1<<k))
                        d[j^(1<<i)^(1<<k)]=min(d[j^(1<<i)^(1<<k)],d[j]+g[i][k]);
            }
        }
    }
    printf("%d\n",sum+d[0]);
    return 0;
}


發佈了290 篇原創文章 · 獲贊 22 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章