1. 程式人生 > >洛谷P1640 連續攻擊遊戲+二分圖匹配

洛谷P1640 連續攻擊遊戲+二分圖匹配

本題是個二分圖匹配問題。
首先我們來複習一下匈牙利演算法:
用臨接矩陣寫的匈牙利:
Code:(洛谷P3386)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 1001
using namespace std;
int match[maxn*100],n,m,e,ans,map[maxn][maxn],vis[maxn*100];
bool dfs(int
x){ for(int i=1;i<=m;i++){ if(map[x][i]==1&&vis[i]==0){ vis[i]=1; if(match[i]==0||dfs(match[i])==1){ match[i]=x; return 1; } } } return 0; } int main(){ cin>>n>>m>>e; for
(int i=1;i<=e;i++){ int x,y; cin>>x>>y; if(x<=n&&y<=m){ map[x][y]=1; } } for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(dfs(i)==1){ ans++; } } cout<<ans; return
0; }

現在我們來看這個題:
把物品屬性a,b,從a,b向i連個有向邊,然後一部分是物品一部分是序號,直接匹配即可。
Code:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#define maxn 100010
using namespace std;
struct Edge{
    int nxt,to;
}edge[2000010];
int n,num_edge,ans,vis[10005],head[10005],match[1000010];
inline void addedge(int from,int to){
    edge[++num_edge].to=to;
    edge[num_edge].nxt=head[from];
    head[from]=num_edge;
}
bool dfs(int x){
    if(vis[x]) return 0;
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
    //    if(!vis[y]){
    //        vis[y]=1;
            if(!match[y]||dfs(match[y])){
                match[y]=x;
                return 1;
            }
    //    }
    }
    return 0;
}
inline void check(){
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(dfs(i)){
            ans++;
        }
        else break;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        //addedge(x,y);
        addedge(x,i);
        addedge(y,i);
    }
    check();
    printf("%d",ans);
    return 0;
}