CF 21D Traveling Graph
題目大意:一張無向圖有n個點(
題解:
如果這張圖是一張歐拉圖的話,那麼存在一條歐拉回路通過所有的邊一次,一定是最小的迴路。如果不是歐拉圖的話,那麼可以通過補一些邊使得它成爲一張歐拉圖。首先floyd處理出兩點之間的最短距離,然後在奇數度頂點之間加邊,將所有的頂點補爲偶數度。實際上是求所有的奇數度頂點的一個最小權完美匹配,可以枚舉二分圖費用流解。那麼最終的解就是所有邊權和加上最小的費用流費用。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 25;
const int MAXE = 10000;
const int INF = 0x3f3f3f3f;
class MCMF{
public:
struct Edge {
int u,v,f,cost,next;
Edge() {};
Edge(int u,int v,int f,int cost,int next):u(u),v(v),f(f),cost(cost),next(next) {};
};
Edge edge[MAXE];
int n,k,head[MAXN],dis[MAXN],pe[MAXN],nEdge;
bool vis[MAXN];
void init() {
memset(head,-1,sizeof(head));
nEdge=0;
}
void addedge(int u,int v,int c,int cost) {
edge[nEdge]=Edge(u,v,c,cost,head[u]);
head[u]=nEdge++;
edge[nEdge]=Edge(v,u,0,-cost,head[v]);
head[v]=nEdge++;
}
bool spfa(int src,int sink) {
memset(vis,false,sizeof(vis));
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(pe,-1,sizeof(pe));
queue<int> q;
q.push(src);
dis[src]=0;
vis[src]=true;
while(!q.empty()) {
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next) {
int f=edge[i].f,v=edge[i].v,cost=edge[i].cost;
if(f&&dis[u]+cost<dis[v]) {
dis[v]=dis[u]+cost;
pe[v]=i;
if(!vis[v]) {
vis[v]=true;
q.push(v);
}
}
}
}
return dis[sink]<INF;
}
int min_cost_max_flow(int src,int sink) {
int ans=0;
while(spfa(src,sink)) {
int delta=INF;
for(int i=pe[sink];i!=-1;i=pe[edge[i].u]) delta=min(delta,edge[i].f);
for(int i=pe[sink];i!=-1;i=pe[edge[i].u]){
edge[i].f-=delta;
edge[i^1].f+=delta;
}
ans+=dis[sink]*delta;
}
return ans;
}
}mcmf;
struct node{
int v,val;
int next;
node(int v,int val,int next):v(v),val(val),next(next){}
node(){}
}edge[MAXE];
int head[MAXN],deg[MAXN],vis[MAXE],nn;
void dfs(int u){
for(int i = head[u];~i;i= edge[i].next){
int v = edge[i].v;
if(vis[i]||vis[i^1]) continue;
vis[i] = 1;
vis[i^1] = 1;
dfs(v);
}
}
void addedge(int u,int v,int w){
edge[nn] = node(v,w,head[u]);
head[u] = nn++;
}
int dis[MAXN][MAXN];
vector<int> V;
void init(){
nn = 0;
memset(head,-1,sizeof(head));
memset(deg,0,sizeof(deg));
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
}
int main(){
int n,m,u,v,w;
while(~scanf("%d%d",&n,&m)){
init();
V.clear();
int ans = 0;
for(int i = 0;i < m;i++){
scanf("%d%d%d",&u,&v,&w);
dis[u][v] = min(dis[u][v],w);
dis[v][u] = dis[u][v];
ans += w;
addedge(u,v,w);
addedge(v,u,w);
deg[u]++;
deg[v]++;
}
dfs(1);
int flag = 0;
for(int i = 1;i <= n;i++) if(deg[i]%2) V.push_back(i);
for(int i = 0;i < nn;i++) if(!vis[i]){ flag = 1; break; }
if(flag){
puts("-1");
continue;
}
for(int k = 1;k <= n;k++)
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
int kk = V.size();
int tmp = 0;
if(kk){
tmp = INF;
for(int i = 1;i < 1<<kk;i++){
int t,cnt = 0;
t = i;
while(t){
if(t&1) cnt++;
t>>=1;
}
if(cnt == kk/2){
mcmf.init();
for(int j = 0;j < kk;j++){
if((i>>j)&1){
mcmf.addedge(0,j+1,1,0);
for(int k = 0;k < kk;k++){
if(!((i>>k)&1)){
mcmf.addedge(j+1,k+1,1,dis[V[j]][V[k]]);
}
}
}
else{
mcmf.addedge(j+1,kk+1,1,0);
}
}
tmp = min(tmp,mcmf.min_cost_max_flow(0,kk+1));
}
}
}
printf("%d\n",ans+tmp);
}
return 0;
}