zoukankan      html  css  js  c++  java
  • USACO Section 2.1

    城堡 The Castle

    爆肝三个小时祭.

    对于第一问其实就是求联通块的个数,第二问求最大联通块所包含的节点,这个可以一个DFS一起求.具体来说我们先存图,设(b[i][j][0/1/2/3])表示点$(i,j)$4面是否有墙,然后每次从一个未访问过的点开始枚举k=0/1/2/3然后向外拓展,同时记录该点属于第几个联通块(第4问有用),该联通块包含节点个数等信息.

    第三问和第四问是一起的.我们直接枚举把哪个墙推掉可以得到最大联通块,因为我们上面DFS记录了每个联通块的节点个数和每个点属于第几个联通块,所以我们枚举的时候只要判断墙两边的节点是否属于不同的联通块,如果是就可以把两个联通块的节点个数相加与maxn比较大小.

    对于第四问,因为是输出方案,且西边最优,南边次优,北墙比东墙优,所以我们先顺序枚举列(保证最西),然后倒序枚举行(保证最南),运用用第三问相同的方法求推掉墙后的新联通块个数是否等于第三问所求即可.如果是直接输出(此时一定是符合题意的最优墙).

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=55;
    int n,m,now,ans1,ans2,ans3;
    int visit[N][N],size[N*N];
    int a[N][N],b[N][N][4];
    inline void dfs(int x,int y){
    	if(x<1||x>n||y<1||y>m)return;
    	visit[x][y]=ans1;++now;++size[ans1];
    	for(int i=0;i<=3;++i){
    		if(b[x][y][i]==1)continue;
    		if(i==0&&!visit[x][y-1])dfs(x,y-1);
    		if(i==1&&!visit[x-1][y])dfs(x-1,y);
    		if(i==2&&!visit[x][y+1])dfs(x,y+1);
    		if(i==3&&!visit[x+1][y])dfs(x+1,y);
    	}
    	return;
    }
    int main(){
    	m=read(),n=read();
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j){
    			a[i][j]=read();
    			for(int k=0;k<=3;++k){
    				if(a[i][j]&(1<<k))b[i][j][k]=1;
    			}
    		}
    	memset(size,0,sizeof(size));
    	while(now<n*m){
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=m;++j)
    				if(visit[i][j]==0){
    					++ans1;dfs(i,j);
    					ans2=max(ans2,size[ans1]);
    				}
    	}
    	printf("%d
    %d
    ",ans1,ans2);
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=m;++j){
    			for(int k=0;k<=3;++k){
    				if(b[i][j][k]){
    					if(k==0){
    						if(j-1<1)continue;
    						if(visit[i][j]==visit[i][j-1])continue;
    						ans3=max(ans3,size[visit[i][j]]+size[visit[i][j-1]]);
    					}
    					if(k==1){
    						if(i-1<1)continue;
    						if(visit[i][j]==visit[i-1][j])continue;
    						ans3=max(ans3,size[visit[i][j]]+size[visit[i-1][j]]);
    					}
    					if(k==2){
    						if(j+1>m)continue;
    						if(visit[i][j]==visit[i][j+1])continue;
    						ans3=max(ans3,size[visit[i][j]]+size[visit[i][j+1]]);
    					}
    					if(k==3){
    						if(i+1>n)continue;
    						if(visit[i][j]==visit[i+1][j])continue;
    						ans3=max(ans3,size[visit[i][j]]+size[visit[i+1][j]]);
    					}
    				}
    			}
    		}
    	}
    	printf("%d
    ",ans3);
    	for(int j=1;j<=m;++j)
    		for(int i=n;i>=1;--i){
    			if(b[i][j][1]&&i-1>=1){
    				if(visit[i][j]!=visit[i-1][j])
    					if(size[visit[i][j]]+size[visit[i-1][j]]==ans3){
    						printf("%d %d N
    ",i,j);
    						return 0;
    					}
    			}
    			if(b[i][j][3]&&i+1<=n){
    				if(visit[i][j]!=visit[i+1][j])
    					if(size[visit[i][j]]+size[visit[i+1][j]]==ans3){
    						printf("%d %d N
    ",i+1,j);
    						return 0;
    					}
    			}
    			if(b[i][j][0]&&j-1>=1){
    				if(visit[i][j]!=visit[i][j-1])
    					if(size[visit[i][j]]+size[visit[i][j-1]]==ans3){
    						printf("%d %d E
    ",i,j-1);
    						return 0;
    					}
    			}
    			if(b[i][j][2]&&j+1<=m){
    				if(visit[i][j]!=visit[i][j+1])
    					if(size[visit[i][j]]+size[visit[i][j+1]]==ans3){
    						printf("%d %d E
    ",i,j);
    						return 0;
    					}
    			}
    		}
        return 0;
    }
    
    

    顺序的分数 Ordered Fractions

    直接枚举出所有的分数,然后sort排序.但是要注意枚举的时候一些细节.比如分母不为零,gcd(分子,分母)=1,分子为零时唯一合法答案是"0/1"等等.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    struct ppx{
    	double val;int i,j;
    }a[40005];
    inline bool cmp(const ppx &x,const ppx &y){return x.val<y.val;}
    inline int gcd(int a,int b){
    	if(b==0)return a;
        return gcd(b,a%b);
    }
    int main(){
    	int n=read(),tot=0;
    	for(int i=0;i<=n-1;++i){
    		for(int j=i+1;j<=n;++j){
    			if(i==0&&j==1){
    				a[++tot].val=(double)i*1.0/j;
    				a[tot].i=i;a[tot].j=j;
    				continue;
    			}
    			if(i==1){
    				a[++tot].val=(double)i*1.0/j;
    				a[tot].i=i;a[tot].j=j;
    				continue;
    			}
    			if(i!=0){
    				if(gcd(i,j)==1){
    					a[++tot].val=(double)i*1.0/j;
    					a[tot].i=i;a[tot].j=j;
    					continue;
    				}
    			}
    		}
    	}
    	sort(a+1,a+tot+1,cmp);
    	for(int i=1;i<=tot;++i)
    		printf("%d/%d
    ",a[i].i,a[i].j);
    	printf("1/1
    ");
        return 0;
    }
    
    

    三值的排序 Sorting a Three-Valued Sequence

    一开始还以为是归并排序求逆序对的模板题,但本题可以不是相邻两个数交换...

    贪心地想,先把a数组从小到大排序存到b数组,然后比较a,b数组的相应位置i如果不同则优先找交换该次两个位置i,j都合法的j交换(即不仅a[j]=b[i]而且a[i]=b[j]),如果没有再选择仅满足a[j]=b[i]的j.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=1005;
    int a[N],b[N];
    int main(){
    	int n=read();
    	for(int i=1;i<=n;++i)a[i]=read(),b[i]=a[i];
    	sort(b+1,b+n+1);
    	int ans=0;
    	for(int i=1;i<=n;++i){
    		if(a[i]!=b[i]){
    			++ans;int bj=0;
    			for(int j=n;j>=i+1;--j){
    				if(a[j]==b[i]&&a[i]==b[j]){bj=1;swap(a[i],a[j]);break;}
    			}
    			if(bj)continue;
    			for(int j=n;j>=i+1;--j){
    				if(a[j]==b[i]){bj=1;swap(a[i],a[j]);break;}
    			}
    		}
    	}
    	printf("%d
    ",ans);
        return 0;
    }
    

    健康的荷斯坦奶牛 Healthy Holsteins

    直接DFS会超时,考虑剪枝.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=50;
    int n,m,a[N][N];
    int v[N],b[N],visit[N];
    inline bool check(){
    	for(int i=1;i<=n;++i)
    		if(b[i]<v[i])return false;
    	return true;
    }
    inline void dfs(int now,int nowm,int goal){
    	if(now>goal){
    		if(check()){
    			printf("%d ",goal);
    			for(int i=1;i<=m;++i)
    				if(visit[i])printf("%d ",i);
    			printf("
    ");
    			exit(0);
    		}
    		return;
    	}
    	if(m-nowm+1<goal-now)return;//剪枝1
    	for(int i=nowm;i<=m;++i){//剪枝2:从上一次选的位置+1开始选
    		if(!visit[i]){
    			visit[i]=1;
    			for(int j=1;j<=n;++j)b[j]+=a[i][j];
    			dfs(now+1,i+1,goal);
    			visit[i]=0;
    			for(int j=1;j<=n;++j)b[j]-=a[i][j];
    		}
    	}
    }
    int main(){
    	n=read();for(int i=1;i<=n;++i)v[i]=read();
    	m=read();
    	for(int i=1;i<=m;++i)
    		for(int j=1;j<=n;++j)
    			a[i][j]=read();
    	for(int i=1;i<=m;++i){
    		for(int j=1;j<=m-i+1;++j){
    			memset(visit,0,sizeof(visit));
    			memset(b,0,sizeof(b));
    			dfs(1,j,i);
    		}
    	}
        return 0;
    }
    

    海明码 Hamming Codes

    本题的难度在于看懂题意???一直不晓得B是干嘛的.

    直接从小到大枚举0到(2^{B+1}-1),然后判断是否跟之前的数距离大于等于D即可,输出前面n个即可.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    int n,m,B,D,ans[105];
    inline bool pd(int x,int y){
        int s=x^y,sum=0;
        for(int i=0;(1<<i)<=s;i++)
            if((1<<i)&s)sum++;
        return sum>=D;
    }
    inline bool check(int x){
        for(int i=1;i<=m;i++)
            if(!pd(x,ans[i]))return false;
        return true;
    }
    int main(){
        n=read(),B=read(),D=read();
        for(int i=0;i<(1<<(B+1))&&m<n;++i)
            if(check(i))ans[++m]=i;
        for(int i=1;i<=n;++i){
            printf("%d ",ans[i]);
            if(i%10==0)puts("");
        }puts("");
        return 0;
    }
    
  • 相关阅读:
    WCF与 Web Service的区别是什么?各自的优点在哪里呢?
    asp、asp.net、ado、ado.net各自区别和联系?
    SQL触发器 inset自学经验
    SQL触发器实例讲解
    特价汇9.9元商品
    sql中数据库连接与断开式连接有什么区别?
    终止线程的三种方法
    selenium设置代理,基于chrome浏览器
    Selenium Webdriver定位元素的几种方式
    spring常用接口 InitializingBean的作用
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11298852.html
Copyright © 2011-2022 走看看