[codeforces 508E]Maximum Matching

题目:Maximum Matching

传送门:http://codeforces.com/contest/1038/problem/E

分析:

一个块拥有{color1,val,color2},两个块相连要求相连处颜色相同,求价值最大的连接方案。

关心到color最大为4,以4种颜色为点,对于每个块,在(color1,color2)间连一条边权为(val)的边,建一张4个点n条边的图。显然,在图上选一条价值最大的路径(或回路)就是答案了。

方法一:

如果这张图本身就是Eular路径(或Eular回路),那就是答案了,不会有方案比全选更优。

如果本身不是Eular路径(或Eular回路),我们可以删掉一些边,使其成为Eular路径(或Eular环路)。

对于两个点而言,最多删去一条边(若删去两条,这两条构成的环可加入答案),删去的边一定是连接这两个点的边中权重最小的。

枚举要删掉的边,对于4个点,两两连接,最多16条边需要考虑是否删除,枚举删掉边的集合st(对该集合状态压缩),对去除该集合中的边的集合求一条Eular路径(或Eular回路)

复杂度:$O(2^16 * 4 * 4 * n)$ 实际上对存在自环的集合是不用考虑的,复杂度:$O(2^16 * n)$

引用:Ashishgup大佬的题解:http://codeforces.com/blog/entry/61692

方法二:

如果两点(u,v)之间存在多条边,每两条边就能走回本身,可从原图中消去,在遍历到u点或v点时加到答案中,注意不要重复加。

为了保证不破坏原图的连通性,那最多只需保留2条边,保留的当然是权值最小的边啦(这些边有可能不被选中,保留权值大的边就可能得不到答案)

对4个点13条边暴力DFS找一条路径即可。这样复杂度与n无关,题目的n可以进一步加强。

#include <bits/stdc++.h>
int e[7][7][121],f[7][7],vis[7];
int ans=0;
void dfs(int x,int tmp){
    for(int y=1;y<=4;++y)if(!vis[x] && !vis[y])tmp+=f[x][y];++vis[x];
    if(tmp>ans)ans=tmp;
    for(int y=1;y<=4;++y)
        if(x!=y && e[x][y][0]>0){
            tmp+=e[x][y][e[x][y][0]];
            --e[x][y][0];--e[y][x][0];
            dfs(y,tmp);
            ++e[x][y][0];++e[y][x][0];
            tmp-=e[x][y][e[x][y][0]];
        }
    --vis[x];for(int y=1;y<=4;++y)if(!vis[x] && !vis[y])tmp-=f[x][y];
}
int main(){
    //freopen("in.txt","r",stdin);
    int n;scanf("%d",&n);
    for(int i=0,u,val,v;i<n;++i){
        scanf("%d %d %d",&u,&val,&v);
        if(v>u)u^=v,v^=u,u^=v;
        e[v][u][++e[v][u][0]]=val;
    }
    for(int i=1;i<=4;++i){
        for(;e[i][i][0];--e[i][i][0])f[i][i]+=e[i][i][e[i][i][0]];
        for(int j=i+1;j<=4;++j){
            std::sort(e[i][j]+1,e[i][j]+e[i][j][0]+1);
            for(;e[i][j][0]>2;e[i][j][0]-=2)f[i][j]+=e[i][j][e[i][j][0]]+e[i][j][e[i][j][0]-1];
            e[j][i][0]=e[i][j][0];e[j][i][1]=e[i][j][1];e[j][i][2]=e[i][j][2];
            f[j][i]=f[i][j];
        }
    }
    dfs(4,0);
    for(int i=1;i<=4;++i)
        dfs(i,0);
    printf("%d",ans);
    return 0;
}

 

方法3:

我们可以设计一个复杂度与n相关的做法,这样颜色数量可以加强。

定义f[i][j][x][y]:[i,j]区间里的链左右端点颜色为(x,y);

转移方程:

1继承:f[i][j][x][y]: max{f[i][k][x][y],f[k+1][j][x][y]};

2拼接:f[i][j][x][y]: max{f[i][k][x][t]+f[k+1][j][t][y], f[k+1][j][x][t]+f[i][k][t][y]};

引用:http://codeforces.com/contest/1038/submission/42602607

方法4:

对于本题而言,在连通块中,每当找到一个环就可以直接加入到答案中。最后可能会剩下一些零星的边,对于只有4个点的图而言的,只有剩下$e_{a,b},e_{c,d}$这种情况要考虑,删除一条就好了,可以从加入答案的边中用权值最小的边替换剩下的边,删掉。等效于删去一条最小边。

找环(实际上不关心环的具体情况,与找Eular路径(回路)方法相同,使用Fleury算法,复杂度O(n))

联通块可用并查集维护。

引用:http://codeforces.com/contest/1038/submission/42587804

 

posted @ 2018-09-14 14:12  hjj1871984569  阅读(361)  评论(0编辑  收藏  举报