【USACO2.1】解题报告

前言

USACO2.1主要内容是图论。其中有几道题是要用深搜做的。而另外几道题则是利用模拟的方法来完成简单图论。
总体来说难度还是比较小的,算是最基础的算法吧。
UASCO:http://train.usaco.org


2.1.3.The Castle

题解


2.1.4.Ordered Fractions

思路:

可以枚举分子和分母,然后判断他们的最小公约数是不是11(其实就是判断是否互质)。如果是的话就将这个分数加入到结构体里面,储存三个变量:

  • 分子ZZ
  • 分母MM
  • 这个分数的值numnum(实数类型)

然后按照分数值排序输出即可。

代码:

/*
ID:ssl_zyc2
TASK:frac1
LANG:C++
*/

#include <cstdio>
#include <algorithm>
using namespace std;

int n,sum;

struct node
{
    int z,m;
    double num;
}a[160*160+10];

bool cmp(node x,node y)
{
    return x.num<y.num;
}

int main()
{
    scanf("%d",&n);
    a[++sum].z=0;
    a[sum].m=1;
    a[sum].num=0;  //分子为0的唯一情况先打上
    for (int i=1;i<=n;i++)
     for (int j=1;j<=i;j++)
      if (__gcd(i,j)==1)  //互质
      {
      	 a[++sum].z=j;
      	 a[sum].m=i;
      	 a[sum].num=(double)j/(double)i/1.0;
      }
    sort(a+1,a+1+sum,cmp);  //排序
    for (int i=1;i<=sum;i++)
     printf("%d/%d\n",a[i].z,a[i].m);
    return 0;
}

2.1.5.Sorting a Three-Valued Sequence

思路:

这道题有点恶心。
读入a[i]a[i],将a[i]a[i]排好序后为b[i]b[i],然后从前往后扫,如果a[i]!=b[i]a[i]!=b[i]就说明这个a[i]a[i]的位置是错误的。那么要分情况。

  1. 先到a[i]a[i]本来应该在的位置,如果这个位置中有为本来应该在a[i]位置的数字,那么就交换两个数字,一次交换就满足了两个数字。
  2. 如果这个位置中没有为本来应该在a[i]位置的数字,那么就随便找一个要到a[i]a[i]位置来的数字交换,一次交换只满足了一个数字。

模拟即可。

代码:

/*
ID:ssl_zyc2
TASK:sort3
LANG:C++
*/

#include <cstdio>
#include <algorithm>
using namespace std;

int n,a[1010],b[1010],cnt;
bool ok;

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    for (int i=1;i<=n;i++)
     if (a[i]!=b[i])  //不相同
     { 
     	ok=false;
     	for (int j=i+1;j<=n;j++)
     	 if (a[i]==b[j]&&a[j]==b[i])   //情况1
     	 {
     	 	swap(a[i],a[j]);
     	 	cnt++;
     	 	ok=true;
     	 	break;
         }
        if (!ok)  //情况2
         for (int j=n;j>i;j--)
          if (a[j]==b[i]) 
          {
          	 swap(a[i],a[j]);
          	 cnt++;
          	 break;
          }
     }
    printf("%d\n",cnt);
    return 0;
}

2.1.6.Healthy Holsteins

思路:

深搜枚举每一个饲料,判断买或者不买。最终取答案最小值即可。
当然如果你英勇一点的话就随机选择那些饲料,多随机几次取最有答案。如果运气好的话应该也是可以过的。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;

int n,m,need[30],sum[30],f[20][30],used[30];

struct node
{
    int ans;
    int used[30];
}ans;

bool check(int k)
{
    for (int i=1;i<=n;i++)
     if (sum[i]<need[i]) return 0;
    if (k<ans.ans) return 1;
    if (k>ans.ans) return 0;  //取最小值
    sort(used+1,used+1+k);
    for (int i=1;i<=k;i++)
     if (used[i]<ans.used[i]) return 1;
     else if (used[i]>ans.used[i]) return 0;
}

void dfs(int x,int s)
{
    if (x>m)
    {
        if (check(s))   //成立
        {
            ans.ans=s;
            for (int i=1;i<=s;i++)
             ans.used[i]=used[i];
            sort(ans.used+1,ans.used+1+s);  //排序
        }
        return;
    }
    dfs(x+1,s);
    used[s+1]=x;
    for (int i=1;i<=n;i++)
     sum[i]+=f[x][i];
    dfs(x+1,s+1);
    used[s+1]=0;
    for (int i=1;i<=n;i++)
     sum[i]-=f[x][i];
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
     scanf("%d",&need[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
     for (int j=1;j<=n;j++)
      scanf("%d",&f[i][j]);
    ans.ans=1e9;
    dfs(1,0);
    printf("%d",ans.ans);
    for (int i=1;i<=ans.ans;i++)
     printf(" %d",ans.used[i]);
    printf("\n");
    return 0;
}
//我这种方法很麻烦,应该有更简单的方法的。

2.1.7.Hamming Codes

思路:

深搜枚举每一位数是00还是11,搜完一个答案后将它和前面的所有答案进行比较,如果都满足要求就记录下这个答案。最后输出时再转换成十进制即可。

代码:

/*
ID:ssl_zyc2
TASK:hamming
LANG:C++
*/

#include <cstdio>
using namespace std;

int n,m,k,ans[70][10],a[10],sum;

void check()
{
	for (int i=1;i<=sum;i++)
	{
		int cnt=0;
		for (int j=1;j<=m;j++)
		 if (a[j]!=ans[i][j]) cnt++;  //不同的位数个数
		if (cnt<k) return;  //不满足要求
	} 
	sum++;
	for (int i=1;i<=m;i++)
	 ans[sum][i]=a[i];  //记录答案
}

void dfs(int x)
{
	if (x>m)  //选择完了
	{
		check();
		return;
	}
	dfs(x+1);  //这一位是0
	if (sum>=n) return; 
	a[x]=1;
	dfs(x+1);  //这一位是1
	if (sum>=n) return;
	a[x]=0;
}

int main()
{
	freopen("hamming.in","r",stdin);
	freopen("hamming.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	sum=1;
	dfs(1);
	for (int i=1;i<=n;i++)
	{
		int s=0,l=0;
		for (int j=m;j>=1;j--)
		{
			s+=(1<<l)*ans[i][j];  //转换成十进制
			l++;
		}
		if (i%10==1) printf("%d",s);
		else if (i%10==0) printf(" %d\n",s);
		else printf(" %d",s);  //USACO神奇的输出要求
	}
	if (n%10) printf("\n");  //USACO神奇的输出要求(末尾必须换行)
	return 0;
}
posted @ 2018-10-28 12:09  全OI最菜  阅读(89)  评论(0编辑  收藏  举报