bzoj1143

最小路径覆盖:有向图的最小路径覆盖为选取最少的路径(路径不相交)能够把图的所有顶点都覆盖(定点不可被重复覆盖)

做法:将有向图变为拆点二分图,然后进行二分图匹配,答案即为n-|最大匹配数|

最小路径可重点覆盖:即路径可相交的路径覆盖

做法:将有向图进行传递闭包后,再进行最小路径覆盖

#include<cstdio>
#include<cstring>
using namespace std;

struct my{
       int v;
       int next;
};

const int maxn=800+10;

int tu[maxn][maxn],fa;
int adj[maxn*2],match[maxn*2];
bool vis[maxn*2];
my bian[maxn*100];

void myinsert(int u,int v){
     bian[++fa].v=v;
     bian[fa].next=adj[u];
     adj[u]=fa;
}

int dfs(int x){
    for (int i=adj[x];i;i=bian[i].next){
        int v=bian[i].v;
        if(!vis[v]){
            vis[v]=true;
            if(!match[v]||dfs(match[v])){
                match[v]=x;
                return 1;
            }
        }
    }
    return 0;
}

int main(){
    int n,m;
    int u,v;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        tu[u][v]=1;
    }
    for (int i=1;i<=n;i++) tu[i][i]=1;
 for (int k=1;k<=n;k++){
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            tu[i][j] |= tu[i][k] && tu[k][j];
        }
    }
 }
 for (int i=1;i<=n;i++) tu[i][i]=0;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            if(tu[i][j]) myinsert(i,j+n);
        }
    }
    int ans=n;
    for (int i=1;i<=2*n;i++){
        for (int j=1;j<=2*n;j++) vis[j]=0;
        if(dfs(i)) ans--;
    }
    printf("%d\n",ans);
return 0;
}

输出方案

即为一直在路径上找到无有向边相连的点

#include<cstdio>
#include<cstring>
using namespace std;

struct my{
       int v;
       int next;
};

const int maxn=800+10;

int tu[maxn][maxn],fa;
int adj[maxn*2],match[maxn*2],hide[maxn],vis2[maxn];
bool vis[maxn*2],succ[maxn*2];
my bian[maxn*100];

void myinsert(int u,int v){
     bian[++fa].v=v;
     bian[fa].next=adj[u];
     adj[u]=fa;
}

int dfs(int x){
    for (int i=adj[x];i;i=bian[i].next){
        int v=bian[i].v;
        if(!vis[v]){
            vis[v]=true;
            if(!match[v]||dfs(match[v])){
                match[v]=x;
                return 1;
            }
        }
    }
    return 0;
}

int main(){
    int n,m;
    int u,v;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        tu[u][v]=1;
    }
    for (int i=1;i<=n;i++) tu[i][i]=1;
 for (int k=1;k<=n;k++){
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            tu[i][j] |= tu[i][k] && tu[k][j];
        }
    }
 }
 for (int i=1;i<=n;i++) tu[i][i]=0;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            if(tu[i][j]) myinsert(i,j+n);
        }
    }
    int ans=n;
    for (int i=1;i<=2*n;i++){
        for (int j=1;j<=2*n;j++) vis[j]=0;
        if(dfs(i)) ans--;
    }
    int top=0;
    printf("%d\n",ans);
    for (int i=1;i<=n;i++) succ[match[i]]=true;
    for (int i=1;i<=n;i++) if(!succ[i]) hide[++top]=i;
    bool flag=true;
    while(flag){
        flag=false;
        for (int i=1;i<=ans;i++){
            for (int j=1;j<=n;j++){
                if(tu[hide[i]][j]) vis2[j]=true;
            }
        }
        for (int i=1;i<=ans;i++){
            if(vis2[hide[i]]){
                flag=true;
                while(vis[hide[i]]) hide[i]=match[hide[i]];
            }
        }
    }
    for (int i=1;i<=ans;i++) printf("%d ",hide[i]);
return 0;
}

 

posted @ 2018-07-28 10:14  lmjer  阅读(126)  评论(0编辑  收藏  举报