1. 程式人生 > >【USACO2.1】解題報告

【USACO2.1】解題報告

前言

USACO2.1主要內容是圖論。其中有幾道題是要用深搜做的。而另外幾道題則是利用模擬的方法來完成簡單圖論。
總體來說難度還是比較小的,算是最基礎的演算法吧。
UASCO:http://train.usaco.org


2.1.3.The Castle

題解


2.1.4.Ordered Fractions

思路:

可以列舉分子和分母,然後判斷他們的最小公約數是不是 1 1

(其實就是判斷是否互質)。如果是的話就將這個分數加入到結構體裡面,儲存三個變數:

  • 分子 Z Z
  • 分母 M M
  • 這個分數的值 n
    u m num
    (實數型別)

然後按照分數值排序輸出即可。

程式碼:

/*
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

思路:

深搜列舉每一位數是 0 0 還是 1 1 ,搜完一個答案後將它和前面的所有答案進行比較,如果都滿足要求就記錄下這個答案。最後輸出時再轉換成十進位制即可。

程式碼:

/*
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;
}