最小点路径覆盖(匈牙利算法)

匹配的一些概念:

完美匹配、完备匹配、最佳匹配

交错轨

可增广轨

匈牙利算法原理:从当前匹配M出发,检查每个未盖点,然后从它出发寻找可增广路,找到可增广路,沿着增广路扩充,直到找不到这样的路停止。

 

JOJ 2730

题意:http://blog.csdn.net/jxy859/article/details/6747413

邻接阵

#include <cstdio>
#include <cstring>

const int N=105;
const int M=105;
bool map[N][M];
//X Y
int match[M];
//Y中与X的哪个匹配,初始为N,表示没有匹配
int vis[N];
//表示X中的元素在dfs过程中是否被标记过
int n,m;

bool dfs (int u)
{
    for (int i=0 ; i<n ; ++i)
        if(map[u][i] && !vis[i])
        {
            vis[i]=true;
            if(match[i]==-1 || dfs(match[i]))
            {
                match[i]=u;
                return true;
            }
        }
    return false;
}

int Maxmatch()
{
    int res=0;
    memset (match , -1 , sizeof(match));
    for (int i=0 ; i<n ; ++i)
    {
        memset (vis , false , sizeof(vis));
        if(dfs(i))res++;
    }
    return res++;
}

int k;
int sc[105][30];

bool valid (int x, int y)
{
    for (int i=0 ; i<k ; ++i)
        if(sc[x][i]>=sc[y][i])
            return false ;
    return true;
}

void build_graph()
{
    memset (map , false , sizeof(map));

    for (int i=0 ; i<n ; ++i)
    {
        for (int j=0 ; j<n ; ++j)
        {
            if(valid(i,j))map[i][j]=true;//有向边;
        }
    }
}

int main ()
{
    int cas;
    scanf("%d",&cas);
    for (int I=1 ; I<=cas ; ++I)
    {
        scanf("%d%d",&n,&k);
        for (int i=0 ; i<n ; ++i)
        {
            for (int j=0 ; j<k ; ++j)
                scanf("%d",*(sc+i)+j);
        }
        build_graph();
        int ans=Maxmatch();
        printf("Case #%d: %d\n",I,n-ans);
    }
    return 0;
}


 

邻接表:

JOJ上已空间上的小优势 第一~~

#include <cstdio>
#include <cstring>

const int N=105;
const int M=105;
///实在摸不准 取max(N,M)做为上界;
const int maxe=10000;
int n,k;
struct Edge {
    int v,next;
}edge[maxe];
int head[N],cnt;
void addedge (int u, int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
///

bool vis[N];
int match[M];
bool dfs (int u)
{
    for (int p=head[u] ; ~p ; p=edge[p].next)
    {
        int v=edge[p].v;
        if(vis[v])continue;
        vis[v]=true;
        if(match[v]==-1 || dfs(match[v]))
        {
            match[v]=u;
            return true;
        }
    }
    return false;
}

int Maxmatch()
{
    int res=0;
    memset (match , -1 , sizeof(match));
    for (int i=0 ; i<n ; ++i)
    {
        memset (vis , 0 , sizeof(vis));
        if(dfs(i))++res;
    }
    return res;
}

int stock[M][30];

bool valid (int a, int b)
{
    for (int i=0 ; i<k ; ++i)
        if(stock[a][i]>=stock[b][i])return false ;
    return true;
}

void build_graph()
{
    memset (head , -1 , sizeof(head));
    cnt=0;
    for (int i=0 ; i<n ; ++i)
    {
        for (int j=0 ; j<n ; ++j)
        {
            if(valid (i,j))addedge (i,j);
        }
    }
}

int main ()
{
    int cas;
    scanf("%d",&cas);
    for (int I=1 ; I<=cas ; ++I)
    {
        scanf("%d%d",&n,&k);
        for (int i=0 ; i<n ; ++i)
        {
            for (int j=0 ; j<k ; ++j)
            {
                scanf("%d",*(stock+i)+j);
            }
        }
        build_graph();
        printf("Case #%d: %d\n",I,n-Maxmatch());
        ///求最小路径覆盖时尤其要注意n
    }
    return 0;
}


 

 

 HDOJ 3991 Harry Potter and the Present II

给出一个无向图,给出p个要求,问至少再需要多少个伙伴才能完成所有的要求。

显然最小路径覆盖。

这题时间卡的很紧,构造网络流会超时,只好现学的匈牙利,1200+MS过的,囧。

#include <cstdio>
#include <cstring>
#define min(a,b) (a<b?a:b)
using namespace std;

const int N=1005;
const int M=1005;
///实在摸不准 取max(N,M)做为上界;
const int maxe=30000000;
const int maxn=2100;
const int inf=0x3fffffff;
const long long Inf=20000000000000ll;

int n,k;
struct Edge {
    int v,next;
}edge[maxe];
int head[N],cnt;
void addedge (int u, int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
///

bool vis[N];
int match[M];
bool dfs (int u)
{
    for (int p=head[u] ; ~p ; p=edge[p].next)
    {
        int v=edge[p].v;
        if(vis[v])continue;
        vis[v]=true;
        if(match[v]==-1 || dfs(match[v]))
        {
            match[v]=u;
            return true;
        }
    }
    return false;
}

int Maxmatch(int nodes)
{
    int res=0;
    memset (match , -1 , sizeof(match));
    for (int i=0 ; i<nodes ; ++i)
    {
        memset (vis , 0 , sizeof(vis));
        if(dfs(i))++res;
    }
    return res;
}
///

long long map[N][N];
int q,m;
long long qt[1005];
int qp[1005];

void build_graph()//o(n*n*k)
{
    memset (head , -1 , sizeof(head));
    cnt=0;
    for (int k=0 ; k<n ; ++k)
    {
        for (int i=0 ; i<n ; ++i)
        {
            for (int j=0 ; j<n ; ++j)
            {
                if(map[i][k]!=Inf && map[k][j]!=Inf &&
                   map[i][j]>map[i][k]+map[k][j])
                    map[i][j]=map[i][k]+map[k][j];
            }
        }
    }
    /*for (int i=0 ; i<n ; ++i)
    {
        for (int j=0 ; j<n ; ++j)
        printf("%d-",map[i][j]);
        printf("\n");
    }*/
    ///处理最短路

    for (int i=0 ; i<q ; ++i)
    {
        for (int j=0 ; j<q ; ++j)
        {
            if(i==j)continue;
            //if(qp[i]==qp[j] && qt[i]<=qt[j]) addedge(i , j);
            if(map[qp[j]][qp[i]]<=qt[j]-qt[i])
                addedge (i , j);
        }
    }
    ///构图
}

int main ()
{
    int u,v,w;
    int cas;
    scanf("%d",&cas);
    for (int I=1 ; I<=cas ; ++I)
    {
        scanf("%d%d%d",&n,&m,&q);
        for (int i=0 ; i<n ; ++i)
            for (int j=0 ; j<n ; ++j)
            {
                if(i!=j)map[i][j]=Inf;
                else map[i][i]=0;
            }
        for (int i=0 ; i<m ; ++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            map[u][v]=map[v][u]=min(map[u][v] , w);//重边?
        }
        for (int i=0 ; i<q ; ++i)
        {
            scanf("%d%d",qp+i,qt+i);
        }
        build_graph();
        printf("Case %d: %d\n",I,q-Maxmatch(q)-1);
    }
    return 0;
}


 

 

 

你可能感兴趣的:(算法,网络,Graph,Build,qt,IM)