LOJ6033「ヤリトレーニング2017 2日目」ボードゲーム(ゲーム理論、二部グラフ、ハンガリーのアルゴリズム)

何不滅のアイデアああ......

ボードは、二部グラフを見に行きたいと思います。(ああSMG)(実際には、学校のシミュレーションゲームは、基本的に同じ質問を持っていますが、直接二部グラフを与えました)

私は二部グラフの最大マッチングを見に行きたいです。(私はどこへ行くか、リングのも、自然をどのように考えますか)

(以下は抜粋であるここ

最大整合方式一部の二部グラフ、上側のハンドを失う不一致から出発点:上側の手を操作するとき、それは不可能であると上側のハンドのみマッチポイントを移動(さもなければない最大の一致)は、単にストレートマッチフリップ側に行きます、上部手を失う、(そうでなければ増強パス、および最大一致矛盾がある)非マッチング点に行きました。

簡単に見つけることが、唯一最大のマッチングでは、特定の開始点かの場合、上側の手は勝ちます。

(注:私はそれが正しいと正確な理由を感じることができるでしょうけれども、私は、ここで少し問題を感じて、私は言うことができないので、クッション)

従って、特定の最大マッチングである場合にのみ上側のハンドに勝つために開始点。

裁判官は、それから、最大の一致のいずれかを見つけることができます。そして、マッチポイントがマッチポイントであり、彼は別の試合を見つけることができれば、それは実際に法的な、あるいは正当ない、そこにあります。

でこれを行うにはハンガリーのアルゴリズム\(O((NM)^ 2)\) 実際定数が小さいでは、速く走る、不満を実行します。


コード

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010,mod=998244353,d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,m,el,cnt,head[maxn],to[maxn],nxt[maxn],dis[maxn],with[maxn],x[maxn],y[maxn],id[111][111],tot;
char mp[111][111];
bool vis[maxn],ans[maxn];
inline void add(int u,int v){
    to[++el]=v;nxt[el]=head[u];head[u]=el;
}
void dfs(int u){
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(~dis[v]) continue;
        dis[v]=dis[u]^1;
        dfs(v);
    }
}
bool dfs2(int u){
    if(vis[u]) return false;
    vis[u]=true;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];
        if(!with[v] || dfs2(with[v])){
            with[with[u]]=0;
            with[u]=v;with[v]=u;
            return true;
        }
    }
    return false;
}
int main(){
    n=read();m=read();
    FOR(i,1,n) scanf("%s",mp[i]+1);
    FOR(i,1,n) FOR(j,1,m) if(mp[i][j]=='.') id[i][j]=++cnt,x[cnt]=i,y[cnt]=j;
    FOR(i,1,n) FOR(j,1,m) if(mp[i][j]=='.'){
        FOR(k,0,3){
            int ti=i+d[k][0],tj=j+d[k][1];
            if(ti<1 || ti>n || tj<1 || tj>m || mp[ti][tj]=='#') continue;
            add(id[i][j],id[ti][tj]);
        }
    }
    MEM(dis,-1);
    FOR(i,1,cnt) if(dis[i]==-1) dis[i]=0,dfs(i);
    FOR(i,1,cnt) if(dis[i]){
        MEM(vis,0);
        dfs2(i);
    }
    FOR(i,1,cnt) if(with[i]){
        MEM(vis,0);
        ans[i]=!dfs2(with[i]);
    }
    FOR(i,1,cnt) if(!ans[i]) tot++;
    printf("%d\n",tot);
    FOR(i,1,cnt) if(!ans[i]) printf("%d %d\n",x[i],y[i]);
}

おすすめ

転載: www.cnblogs.com/1000Suns/p/11806024.html