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;
}

猜你喜欢

转载自www.cnblogs.com/lmjer/p/9380884.html
今日推荐