[POJ 4001-4010][2011 Asia Fuzhou Regional Contact]2011 ACM福州競技区現地試合題解(更新継続)

12947 ワード

A:Xiangqi(http://poj.org/problem?id=4001)
気持ち悪い模擬問題です.書く時は気をつけてください.リストボード上の全ての点で、黒を落とすかどうかを判断して、次の位置に着けばいいです.考えは簡単ですが、ACも難しいです.
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

#define MAXN 100

using namespace std;

int map[MAXN][MAXN],N; //map[x][y]=kind    (x,y),  kind  ,1->  2->  3->  4->  5->  ,  x,  y
int xx[]={1,-1,0,0},yy[]={0,0,1,-1}; //        
int mx[]={-2, -2, -1, 1, 2, 2, 1, -1},my[]= {1, -1, 2, 2, 1, -1, -2, -2} ;//      

bool inScope(int x,int y) //  (x,y)          
{
    if(y<4||y>6||x<1||x>3) return false;
    return true;
}

bool inMap(int x,int y) //  (x,y)      
{
    if(x<1||x>10||y<1||y>9) return false;
    return true;
}

int getNum(int x1,int y1,int x2,int y2) // (x1,y1) (x2,y2)       
{
    if((x1==x2&&y1==y2)||(x1!=x2&&y1!=y2)) return -1;
    if(x1==x2)
    {
        int cnt=0;
        if(y1>y2) swap(y1,y2);
        for(int i=y1+1;i<y2;i++)
            if(map[x1][i]) cnt++;
        return cnt;
    }
    if(y1==y2)
    {
        int cnt=0;
        if(x1>x2) swap(x1,x2);
        for(int i=x1+1;i<x2;i++)
            if(map[i][y1]) cnt++;
        return cnt;
    }
}

bool check(int x,int y) //   (x,y),       true,       false
{
    for(int i=1;i<=10;i++)
        for(int j=1;j<=9;j++)
        {
            switch(map[i][j])
            {
                case 5:break;
                case 1: // 
                    {
                        if(getNum(x,y,i,j)==0)
                        {
                            //cout<<x<<' '<<y<<' '<<endl<<i<<' '<<j<<' '<<map[i][j]<<endl;
                            return true;
                        }
                        break;
                    }
                case 2: // 
                    {
                        if(getNum(x,y,i,j)==0)
                        {
                            //cout<<x<<' '<<y<<' '<<endl<<i<<' '<<j<<' '<<map[i][j]<<endl;
                            return true;
                        }
                        break;
                    }
                case 4: // 
                    {
                        if(getNum(x,y,i,j)==1)
                        {
                            //cout<<x<<' '<<y<<' '<<endl<<i<<' '<<j<<' '<<map[i][j]<<endl;
                            return true;
                        }
                        break;
                    }
                case 3: // 
                    {
                        for(int dir=0;dir<8;dir++)
                        {
                            int tx=i+mx[dir],ty=j+my[dir]; //       (tx,ty)
                            if(!inMap(tx,ty)) continue;
                            if(map[tx][ty]!=5) continue; //       
                            if(mx[dir]==2) if(inMap(i+1,j)&&map[i+1][j]) break; //     
                            if(mx[dir]==-2) if(inMap(i-1,j)&&map[i-1][j]) break;
                            if(my[dir]==2) if(inMap(i,j+1)&&map[i][j+1]) break;
                            if(my[dir]==-2) if(inMap(i,j-1)&&map[i][j-1]) break;
                            //cout<<x<<' '<<y<<' '<<endl<<i<<' '<<j<<' '<<map[i][j]<<endl;
                            return true;
                        }
                        break;
                    }
            }
        }
    return false;
}

int main()
{
    while(1)
    {
        memset(map,0,sizeof(map));
        int hx,hy,x,y,flag=1,now=0; //    (hx,hy),       ,flag=0
        char s[3];
        scanf("%d%d%d",&N,&hx,&hy);
        if(N==0&&hx==0&&hy==0) return 0;
        map[hx][hy]=5;
        for(int i=0;i<N;i++)
        {
            scanf("%s%d%d",s,&x,&y);
            switch(s[0])
            {
                case 'G':{map[x][y]=1; break;}
                case 'R':{map[x][y]=2; break;}
                case 'H':{map[x][y]=3; break;}
                case 'C':{map[x][y]=4; break;}
            }
        }
        for(int dir=0;dir<4;dir++)
        {
            int bak; //  
            int tx=hx+xx[dir],ty=hy+yy[dir]; //        (tx,ty)
            if(!inScope(tx,ty)) continue;
            bak=map[tx][ty];
            map[tx][ty]=5;
            map[hx][hy]=0;
            if(!check(tx,ty)) {flag=0; break;} //      
            map[tx][ty]=bak;
            map[hx][hy]=5;
        }
        if(flag) printf("YES
"); else printf("NO
"); } return 0; }
B:Alice's Mooncake Shop(http://poj.org/problem?id=4002)
単調な隊列で,この問題はまだはっきりしていないので,構想を書かない.
#include <iostream>
#include <stdio.h>
#include <string.h>

#define MAXT 3000

using namespace std;

struct Node
{
    int num,time; //  :   t    num;  :   t  num   
}q[MAXT*4],order[MAXT];

int MonDay[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; //      

int mon(char *s)
{
    if(strcmp(s,"Jan")==0) return 1;
    if(strcmp(s,"Feb")==0) return 2;
    if(strcmp(s,"Mar")==0) return 3;
    if(strcmp(s,"Apr")==0) return 4;
    if(strcmp(s,"May")==0) return 5;
    if(strcmp(s,"Jun")==0) return 6;
    if(strcmp(s,"Jul")==0) return 7;
    if(strcmp(s,"Aug")==0) return 8;
    if(strcmp(s,"Sep")==0) return 9;
    if(strcmp(s,"Oct")==0) return 10;
    if(strcmp(s,"Nov")==0) return 11;
    if(strcmp(s,"Dec")==0) return 12;
}

bool isLeapYear(int year) //    
{
    return year%4==0&&(year%100||year%400==0);
}

int getHour(int year,int month,int day,int hour) //      
{
    int tot=0;
    for(int i=2000;i<year;i++)
    {
        if(isLeapYear(i)) tot+=366; //  366 
        else tot+=365; //  365 
    }
    for(int i=1;i<month;i++)
    {
        if(isLeapYear(year)&&i==2) tot+=29; //  2 29 
        else tot+=MonDay[i];
    }
    tot+=day-1; //    
    return tot=tot*24+hour;
}

int main()
{
    while(1)
    {
        char s[10];
        int n,m,year,month,day,hour,T,S,cost,h=0,t=0,p=0;
        long long int sum=0;
        scanf("%d%d",&n,&m);
        if(n==0&&m==0) return 0;
        for(int i=0;i<n;i++)
        {
            scanf("%s%d%d%d%d",s,&day,&year,&hour,&order[i].num);
            order[i].time=getHour(year,mon(s),day,hour); //      ,       
        }
        scanf("%d%d",&T,&S);
        for(int i=0;i<m;i++)
        {
            scanf("%d",&cost);
            while(h<t&&q[t-1].num+S*(i-q[t-1].time)>=cost) t--; //   x   ,      j,     i,     s,      cost[x]+(j-i)*s,       
            q[t].num=cost,q[t++].time=i; //     
            while(p<n&&i==order[p].time)  //   p   
            {
                while(q[h].time+T<i) h++; //                 (        ),    
                sum+=(q[h].num+S*(i-q[h].time))*order[p++].num; //         
            }
        }
        printf("%lld
",sum); } return 0; }
F:Genghis Khan the Conquerer(http://poj.org/problem?id=4006)
最小生成ツリーは、Q回の問い合わせに対して、最小生成ツリー+1回のDFSを実行して、最小生成ツリー上の2つの隣接ノードの非樹端のうちの最短辺を求めて、Q回の問い合わせに対して、更新された端が木の端にある場合は、ツリーの端以外の最短辺または更新後の辺を選択して、ツリー上の既存辺の代わりに選択します.O(Q)の複雑さで解決できます.
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>

#define INF 1000000000
#define MAXM 3010 // 
#define MAXN 9000100 // 

using namespace std;

vector<int>mst[MAXM];

struct edge
{
    int u,v,c;
    bool operator<(const edge&rhs)const
    {
        return c<rhs.c;
    }
}edges[MAXN];

int nCount=0; //total edges
int num[MAXM][MAXM],best[MAXM][MAXM];
int f[MAXM];
int inTree[MAXM][MAXM];

int min(int a,int b)
{
	if(a<b) return a;
	return b;
}

int findSet(int x)
{
	if(f[x]==x) return x;
	return f[x]=findSet(f[x]);
}

void Union(int a,int b)
{
	f[a]=b;
}

double Kruscal(int n,int m)
{
	int i,j;
	double ans=0;
	sort(edges,edges+m);
	for(i=0;i<m;i++)
	{
		int t1=findSet(edges[i].u);
		int t2=findSet(edges[i].v);
		if(t1!=t2)
		{
			Union(t1,t2);
			ans+=edges[i].c;
			mst[edges[i].u].push_back(edges[i].v);
			mst[edges[i].v].push_back(edges[i].u);
			inTree[edges[i].u][edges[i].v]=1;
			inTree[edges[i].v][edges[i].u]=1;
		}
	}
	return ans;
}

int dfs(int rt,int u,int fa)
{
	int i,j,s=INF;
	for(i=0;i<mst[u].size();i++) // u      i  
	{
		int v=mst[u][i]; //    u   v
		if(v==fa) continue;
		int tmp=dfs(rt,v,u);
		s=min(s,tmp);
		best[u][v]=best[v][u]=min(best[u][v],tmp);
	}
	if(rt!=fa) //  
		s=min(num[rt][u],s);
	return s;
}

int main()
{
	int i,j;
	int N,M,X,Y,C,Q;
	while(1)
	{
		double ANS=0;
		for(i=0;i<MAXM;i++)
        {
            mst[i].clear();
            f[i]=i;
            for(j=0;j<MAXM;j++)
            {
                num[i][j]=best[i][j]=INF;
                inTree[i][j]=0;
            }
		}
		scanf("%d%d",&N,&M);
		if(N==0&&M==0)
			return 0;
		for(i=0;i<M;i++)
		{
			scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].c);
            num[edges[i].u][edges[i].v]=num[edges[i].v][edges[i].u]=edges[i].c;
		}
		double minDis=Kruscal(N,M);
		for(i=0;i<N;i++)
			dfs(i,i,-1);
		scanf("%d",&Q);
		for(i=1;i<=Q;i++)
		{
			scanf("%d%d%d",&X,&Y,&C);
			if(!inTree[X][Y]) ANS+=minDis; //      ,       
			else //  ,        X<->Y              C   
			{
				ANS+=minDis-num[X][Y]+min(best[X][Y],C);
			}
		}
		printf("%.4lf
",ANS/(Q*1.0)); } return 0; }
G:Floood-it(http://poj.org/problem?id=4007)
暴挙する.試合の時はコントで展開して、逆康で展開して重さを判定すると思っていましたが、実際には裸IDA*でも大丈夫です.IDA*が検索する前にまず一回flook操作をしてください.でないと、サイクルが死にます.気がふさぎます.
//IDA*
#include <iostream>
#include <stdio.h>
#include <string.h>

#define MAXN 10

using namespace std;

int map[MAXN][MAXN],xx[4]={1,-1,0,0},yy[4]={0,0,1,-1},status[MAXN][MAXN]; //status[i][j]=1  (i,j)    ,     ,2  (i,j)    ,      ,3  (i,j)    ,       
int N,depth;

bool check(int x,int y) //  (x,y)    ,   false
{
    if(x>N||x<1||y>N||y<1) return false;
    return true;
}

void flood(int x,int y,int col) // (x,y),   col      flood
{
    status[x][y]=1; //          
    for(int dir=0;dir<4;dir++)
    {
        int tx=x+xx[dir]; //        (tx,ty)
        int ty=y+yy[dir];
        if(!check(tx,ty)) continue; //     
        if(status[tx][ty]==1) continue; //     ,  
        if(map[tx][ty]==col) //       
            flood(tx,ty,col);
        else status[tx][ty]=2; //          ,   (tx,ty)          
    }
}

int get_cnt(int col) //      col     ,         
{
    int cnt=0;
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
        {
            if(status[i][j]==2&&map[i][j]==col) //         col         ,          ,        status  ,          
            {
                cnt++; //  
                flood(i,j,col);
            }
        }
    return cnt;
}

int h() //    ,          ,       ,                 
{
    int tot=0;
    bool flag[6];
    memset(flag,false,sizeof(flag));
    for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
        {
            if(status[i][j]!=1&&!flag[map[i][j]]) //         ,          
            {
                tot++;
                flag[map[i][j]]=true;
            }
        }
    return tot;
}

bool IDAstar(int dep) //    dep      ,      true,     false
{
    if(dep==depth) return h()==0; //          ,             
    if(dep+h()>depth) return false; //      ,    false
    for(int i=0;i<6;i++) //  i   
    {
        int now[MAXN][MAXN]; //now      status
        memcpy(now,status,sizeof(status));
        if(get_cnt(i)==0) //         ,     
            continue;
        if(IDAstar(dep+1)) return true; //      ,  true
        memcpy(status,now,sizeof(now)); // status    
    }
    return false; //       ,     
}

int main()
{
    while(1)
    {
        memset(map,0,sizeof(map));
        memset(status,0,sizeof(status));
        scanf("%d",&N);
        if(N==0) return 0;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                scanf("%d",&map[i][j]);
        flood(1,1,map[1][1]); //     
        depth=h();
        while(1)
        {
            if(IDAstar(0)) break; //       
            depth++; //          ,    (    )
        }
        printf("%d
",depth); // } return 0; }