【USACO2.1】解題報告
阿新 • • 發佈:2018-11-10
前言
USACO2.1主要內容是圖論。其中有幾道題是要用深搜做的。而另外幾道題則是利用模擬的方法來完成簡單圖論。
總體來說難度還是比較小的,算是最基礎的演算法吧。
UASCO:http://train.usaco.org
2.1.3.The Castle
2.1.4.Ordered Fractions
思路:
可以列舉分子和分母,然後判斷他們的最小公約數是不是
(其實就是判斷是否互質)。如果是的話就將這個分數加入到結構體裡面,儲存三個變數:
- 分子
- 分母
- 這個分數的值 (實數型別)
然後按照分數值排序輸出即可。
程式碼:
/*
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]位置的數字
,那麼就隨便找一個要到 位置來的數字交換,一次交換隻滿足了一個數字。
模擬即可。
程式碼:
/*
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
思路:
深搜列舉每一位數是 還是 ,搜完一個答案後將它和前面的所有答案進行比較,如果都滿足要求就記錄下這個答案。最後輸出時再轉換成十進位制即可。
程式碼:
/*
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;
}