ural 1124 Mosaic

http://acm.timus.ru/problem.aspx?space=1&num=1124


题目大意是,有M种卡片,每种有N个,初始时放在M个盒子里,每个盒子里有N张,但是可能有某些卡片放错了位置,因此需要进行一些

移动,最后使得每张卡片都放到它应该在的盒子(第1种卡片都放入盒子1,第2种卡片都放入盒子2……)。一次移动是指把一张卡片从

当前手边的盒子里拿出放到另一个盒子,或者不拿卡片,只是把手从当前的盒子处移到另一个盒子处。

容易联想到欧拉路,如果盒子i里面有一张卡片j,就把i,j之间连一条边,表示至少要有一次从i到j的移动。容易发现这样建图后每个点

的出度必然等于入度(因为初始时盒子里就有N张卡片,后面拿出多少张也就要拿入多少张),也就是说对于每个连通分量,欧拉回路必

定存在,最少的移动次数实际上就是边的总数。在不同的连通分量之间必然要有一次空着手的移动。因此最后的答案就是 边数+连通分

量数-1(第一次开始时手可以在任何位置)。

 

#include <stdio.h>
#include<string.h>

#define MAXN 502

int father[MAXN];
bool exist[MAXN];

int find(int x)
{
    int i,t;
    for(i=x;father[i]>0;i=father[i]) ;
    while(x!=i)
    {
        t=father[x];
        father[x]=i;
        x=t;
    }
    return i;
}
void merge(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return;
  //  father[fy]=fx;
    if(father[fx]>father[fy])
    {
        father[fy]+=father[fx];
        father[fx]=fy;
    }
    else
    {
        father[fx]+=father[fy];
        father[fy]=fx;
    }
}

int main()
{
    int i,j,k,M,N;
    while(scanf("%d %d",&M,&N)!=EOF)
    {
        memset(father,-1,sizeof(father));
        memset(exist,false,sizeof(exist));
        int ans=0;
        for(i=1;i<=M;i++)
        {
            for(j=1;j<=N;j++)
            {
                scanf("%d",&k);
                if(k!=i)
                {
                    merge(k,i);
                    exist[i]=exist[k]=true;
                    ans++;
                }
            }
        }
        for(i=1;i<=M;i++)
            if(exist[i] && father[i]<0) ans++;
        if(--ans < 0) ans=0;
        printf("%d\n",ans);
    }
}

posted @ 2010-08-26 01:30  菜到不得鸟  阅读(332)  评论(0)    收藏  举报