您的位置:首页 > 其它

zoj 2342 Roads

2016-04-29 23:39 435 查看
  在最优策略中,我们只会减少石头路的费用,增加烂泥路的费用,设这个改变量为l(x)。由于前n−1条边是生成树,对第n~m条边中的每一条,它的加入会形成一个圈。在最优解的情况下,圈中的任意一条石头路费用不大于烂泥路的费用。把石头路看作二分图的X部,烂泥路看作Y部,可以得到关于改变量l(x)的不等式。这个模型直接套二分图最优匹配就行,求出的可行顶标就是改变量。

  KM算法还是略神奇的,有待加强理解!

#include <bits/stdc++.h>

using namespace std;

const int maxn = 66;
const int maxN = 410;

int lx[maxN];
int ly[maxN];
int sx[maxN];
int sy[maxN];
int match[maxN];
int weight[maxN][maxN];
int sz;

bool path(int u){

sx[u] = true;
for(int v=1;v<=sz;v++){
if(!sy[v] && lx[u] + ly[v] == weight[u][v]){
sy[v] = true;
if(match[v] == -1 || path(match[v])){
match[v] = u;
return true;
}
}
}
return false;
}

int bestmatch(){
int i,j;
for(i=1;i<=sz;i++){
lx[i] = 0x80000000;
ly[i] = 0;
for(j=1;j<=sz;j++){
if(lx[i]<weight[i][j]){
lx[i] = weight[i][j];
}
}
}
memset(match,-1,sizeof(match));

for(int u=1;u<=sz;u++){
while(1){
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
if(path(u)){
break;
}
int dx = 0x7fffffff;
for(i=1;i<=sz;i++){
if(sx[i]){
for(j=1;j<=sz;j++){
if(!sy[j]){
dx = min(lx[i]+ly[j]-weight[i][j],dx);
}
}
}
}
for(i=1;i<=sz;i++){
if(sx[i]){
lx[i] -= dx;
}
if(sy[i]){
ly[i] += dx;
}
}
}
}
int sum = 0;
for(i=1;i<=sz;i++){
sum+=weight[match[i]][i];
}
return sum;
}

vector<int> adj[maxn];

int height[maxn];
int p[maxn];
int pEdge[maxn];

struct Edge{
int u;
int v;
int w;
Edge(int u,int v,int w):u(u),v(v),w(w){
}
Edge(){
}
}edges[maxN];

void predfs(int u){
for(int i=0;i<adj[u].size();i++){
int v = edges[adj[u][i]].u;
if(v==u){
v = edges[adj[u][i]].v;
}
if(v!=p[u]){
p[v] = u;
pEdge[v] = adj[u][i];
height[v] = height[u] + 1;
predfs(v);
}
}
}

void init(){
memset(weight,0,sizeof(weight));
memset(adj,0,sizeof(adj));
memset(p,0,sizeof(p));
}

void addedge(int u,int v,int id){
adj[u].push_back(id);
adj[v].push_back(id);
}

int uu[maxN];
int vv[maxN];
int ww[maxN];

int main(){
int t;
cin>>t;
while(t--){
init();

int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>uu[i]>>vv[i]>>ww[i];
if(i<n){
edges[i] = Edge(uu[i],vv[i],ww[i]);
addedge(uu[i],vv[i],i);
}else{
}
}

predfs(1);

int szX = n-1;
int szY = m-n+1;
sz = max(szX,szY);
int Yid = 1;

for(int i=n;i<=m;i++){
int u = uu[i];
int v = vv[i];
if(height[u]>height[v]){
swap(u,v);
}

int Xid;
int sum;

// move v
while(height[v] > height[u]){
Xid = pEdge[v];
sum = ww[Xid] - ww[i];
if(sum<0){
sum = 0;
}
weight[Xid][Yid] = sum;
v = p[v];
}

//move u and v
while(u!=v){
Xid = pEdge[u];
sum = ww[Xid] - ww[i];
if(sum<0){
sum = 0;
}
weight[Xid][Yid] = sum;

Xid = pEdge[v];
sum = ww[Xid] - ww[i];
if(sum<0){
sum = 0;
}
weight[Xid][Yid] = sum;

u = p[u];
v = p[v];
}

Yid++;
}

/*
for(int i=1;i<=sz;i++){
for(int j=1;j<=sz;j++){
cout<<weight[i][j]<<" ";
}
cout<<endl;
}
*/

bestmatch();

for(int i=1;i<=szX;i++){
cout<<ww[i] - lx[i]<<endl;
}
for(int i=1;i<=szY;i++){
cout<<ww[i+n-1] + ly[i]<<endl;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  km算法 最优匹配