【二分圖匹配複習】 noi2011 game

 

        暑假做這道題時,糾結了N久=。=......最後跑到5機房來問秋哥和奧特曼,結果.......就陪着他們在看魁拔(>.<)......

        反正就是沒有寫啦。亡羊補牢,也算是對二分圖匹配的複習吧。

      

        操作可以轉化爲路徑問題,進行黑白染色之後,變成二分圖。

        這道題的關鍵之處在於,先手必勝點是必定出現在最大匹配中的點。

        這個不難理解,一旦出現在最大匹配中,先手必定能沿着匹配邊走,而後手只能沿着非匹配邊走,最終無路可走。

 

        而如果兔兔操作時處於先手必勝點,操作後的點仍然是先手必勝點,它就必定犯了錯。


         爲了圖思維方便,直接寫了k次匈牙利,慢是慢了點,但是沒有什麼糾結的地方。

 

        

# include <cstdlib>
# include <cstdio>
# include <cstring>
 
using namespace std;
 
const int maxn=40+5;
int ans[1000+5],id[maxn][maxn], lk[maxn*maxn][maxn*maxn],point[maxn*maxn];
bool v[maxn*maxn], can[maxn*maxn];
int n,m,sx,sy,mx[4],my[4];
 
inline int abs(int x){return x<0?-x:x;};
 
void link(int x, int y){lk[x][++lk[x][0]]=y;}
 
void prepare()
{
    int i,j,k,ti,tj;
    for (i = 1; i <= n; i++)
      for (j = 1; j <= m; j++)
        if (abs(i-sx+j-sy) & 1) can[(i-1)*m+j]=(1==id[i][j]); 
          else can[(i-1)*m+j] = (-1==id[i][j]);
    for (i = 1; i <= n; i++)
      for (j = 1; j <= m; j++)
        if (can[(i-1)*m+j] && id[i][j]==-1)
          for (k = 0; k < 4; k++)
          {
                ti=i+mx[k], tj= j+my[k];
                if (can[(ti-1)*m+tj] && id[ti][tj]==1) 
                   link((i-1)*m+j, (ti-1)*m+tj);
          }
}
 
bool dfs(int x)
{
    int i,ne; v[x]=true;
    for (i = 1; i <= lk[x][0]; i++)
    {
        ne=lk[x][i];
        if ((!v[ne])&&can[ne])
        {
            v[ne]=true;
            if (point[ne]==0||dfs(point[ne]))
            {point[ne]= x; return true;}
        }
    }
    return false;
}
 
bool check(int x, int y)
{
    int i,j,sum=0;
    memset(point,0,sizeof(point));
    for (i = 1;i <= n; i++)
      for (j = 1; j <= m; j++)
        if (can[(i-1)*m+j] && id[i][j]==-1)
        {
          memset(v,false,sizeof(v));
          if (dfs((i-1)*m+j)) sum++;
        }
    memset(point,0,sizeof(point));
    can[(x-1)*m+y]=false;
    for (i = 1;i <= n; i++)
      for (j = 1; j <= m; j++)
        if (can[(i-1)*m+j] && id[i][j]==-1)
        {
          memset(v,false,sizeof(v));
          if (dfs((i-1)*m+j)) sum--;
        }
    if (sum) return true; else return false;
}
 
int main()
{
    int test,i,j,x,y; char c;
    //freopen("game.in", "r", stdin);
    //freopen("game.out", "w", stdout);
    scanf("%d%d\n", &n, &m);
    mx[0]=1;mx[1]=0;mx[2]=-1;mx[3]=0;
    my[0]=0;my[1]=1;my[2]=0;my[3]=-1;
    for (i = 1; i <=n; i++)
    {
      for (j =1; j <=m; j++)
      {
            scanf("%c", &c);
            if (c=='O') id[i][j] = 1;
            else if (c=='X') id[i][j] = -1;
            else sx=i,sy=j, id[i][j]=-1;
      }
      scanf("\n");
    }
    prepare();
    scanf("%d", &test);
    for (i = 1; i <= test; i++)
    {
        scanf("%d%d", &x, &y);
        bool win=check(sx,sy); can[(sx-1)*m+sy]=false;
        sx=x,sy=y;
        scanf("%d%d", &x, &y);
        if (win && check(sx,sy)) ans[++ans[0]]=i; can[(sx-1)*m+sy]=false;
        sx=x,sy=y;
    }
    printf("%d\n", ans[0]);
    for (i = 1; i <= ans[0]; i++)
       printf("%d\n", ans[i]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章