此博客原文地址:https://www.cnblogs.com/BobHuang/p/12312129.html
1.6172: Alice視察
本題目比較困難,我們將信息傳遞出去,而且要滿足最短的,那么其實只需要n-1條邊,是一棵無向樹。在數據結構中有“最小生成樹”,有兩個算法,分別是Kruskal(加邊)及Prime(加點)。這個題目數據量比較小,不卡算法,你可以實現任一算法AC。題解所用的是Kruskal。
這個算法的思想可以這樣理解,我將所有的邊按照權值進行排序,我必定會先選擇最小的邊,怎么確定這個邊可以用另一數據結構“並查集”,他也是一棵無向樹。沒有連接這條邊肯定要選,所以也有點貪心的意思。最后n-1條邊將n個點連接起來就是最小的。
用C++11進行提交,否則CE
#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = 1005;
//定義並查集父親數組
int fa[N];
//並查集查找祖先函數
int Find(int x)
{
//相等,已經找到
if (x == fa[x])
return x;
//沒有,壓縮一下
return fa[x] = Find(fa[x]);
}
//並查集聯合函數
void Union(int x, int y)
{
//尋找x的祖先
x = Find(x);
//尋找y的祖先
y = Find(y);
//不一個進行合並
if (x != y)
fa[x] = y;
}
//邊數組,和用struct數組一樣
pair<int, pair<int, int>> V[M];
#define fi first
#define se second
int main()
{
int n, m;
cin >> n >> m;
//並查集父親數組初始化
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 0, x, y, z; i < m; i++)
{
cin >> x >> y >> z;
V[i] = {z, {x, y}};
}
//pair運算符不需要重載
sort(V, V + m);
int ans = 0;
for (int i = 0, x, y, z; i < m; i++)
{
//兩個點不相連,加入
if (Find(V[i].se.fi) != Find(V[i].se.se))
{
ans += V[i].fi;
Union(V[i].se.fi, V[i].se.se);
}
}
cout << ans << "\n";
}
2.6178: Alice運快遞
第一問是一個很經典的01背包問題,一個物品可以選一次,所以我們這時候的狀態是從前一個狀態過來的。當前物品是否可以放下,是不是更大都是需要我們考慮的。01背包只能選一次,我們可以優化只用一維dp數組,第二重循環需要倒着進行。
第二問是個很簡單的貪心問題,我們可以選擇體積最小的貨物裝上。
#include <bits/stdc++.h>
using namespace std;
int w[1005], c[1005], dp[100005];
int main()
{
int m, n;
while (cin >> m >> n)
{
for (int i = 0; i < n; i++)
cin >> w[i] >> c[i];
//求最大,dp數組清空
memset(dp, 0, sizeof(dp));
//循環訪問物品
for (int i = 0; i < n; i++)
{
//對dp[i-1][j]查詢,看看還能不能放下
//少一維循環,必須從大到小保證只放一次
for (int j = m; j >= w[i]; j--)
dp[j] = max(dp[j], dp[j - w[i]] + c[i]);
}
sort(w, w + n);
int ans = 0, sum = 0;
for (int i = 0; i < n; i++)
{
//貪心只取最小
if (sum + w[i] <= m)
sum += w[i], ans++;
else
break;
}
cout << dp[m] << " " << ans << "\n";
}
return 0;
}
3.6173: 相同行程查詢
這個題目有些困難,我們需要知道這個人的車次,之后我們會找到人然后對應到這個車次。最終我們要查詢的是車次,當然我們可以進行排序之后二分。不過這個題目有個更好用的東西,叫map,是stl中的一個。map<key,value>也叫鍵值對,前面可以把放鍵,可以理解為就是一個下標,后面放值。所以就是人和車次的map以及車次和人數的map。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
//m為人和車次的鍵值對
map<string, string> m;
//p為車次和人數的鍵值對
map<string, int> p;
int main()
{
int n, a;
string x, y;
cin >> n;
while (n--)
{
//讀入車次和人數
cin >> x >> a;
while (a--)
{
//讀入人名
cin >> y;
//建立人名和車次的鍵值對
m[y] = x;
}
}
cin >> n;
while (n--)
{
//讀入生病的人
cin >> y;
//對生病的車次進行+1操作
p[m[y]]++;
}
cin >> n;
while (n--)
{
cin >> x;
//直接輸出車次上生病的人數
cout << p[x] << "\n";
}
return 0;
}
4.6177: Alice玩漢諾
這個題目我們可以采用常規做法,就是我們遞歸的時候可以統計移動次數。
當然也可以找到遞推式,數量級大的情況就必須使用遞推式了。
A->B=(上一次)A->C->B
B->C=(上一次)B->A->C
C->A=(上一次)C->B->A
我這里用了遞歸寫法,我們可以設置變量去統計他們,在每次移動的時候去統計。
#include <bits/stdc++.h>
using namespace std;
int ans[8];
void move(char a, char b)
{
//進行判斷歸到不同變量
if (a == 'A' && b == 'B')
ans[0]++;
if (a == 'A' && b == 'C')
ans[1]++;
if (a == 'B' && b == 'A')
ans[2]++;
if (a == 'B' && b == 'C')
ans[3]++;
if (a == 'C' && b == 'A')
ans[4]++;
if (a == 'C' && b == 'B')
ans[5]++;
}
void hanoi(int n, char a, char b, char c)
{
if (n == 0)
return;
hanoi(n - 1, a, c, b);
//必然把a移動到c
move(a, c);
hanoi(n - 1, b, a, c);
}
int main()
{
int n;
while (cin >> n)
{
//清空ans數組
memset(ans, 0, sizeof(ans));
hanoi(n, 'A', 'B', 'C');
//一次輸出答案
cout << "A->B: " << ans[0] << "\n";
cout << "A->C: " << ans[1] << "\n";
cout << "B->A: " << ans[2] << "\n";
cout << "B->C: " << ans[3] << "\n";
cout << "C->A: " << ans[4] << "\n";
cout << "C->B: " << ans[5] << "\n";
}
return 0;
}
5.6179: Alice排數字
其實我們可以給其中的8和2拿出來看看有多少個282,排列一定是282828282····
也就是28不斷循環的,其中282的個數和2和8均有關,n個2就有n-1個282,m個8就有m個282,兩者取小,當然不能是負數。
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
while (cin >> s)
{
int a[10] = {0};
for (int i = 0; s[i]; i++)
{
//'0'是48,數字下標所對位置++
a[s[i] - '0']++;
}
//2的個數和8的個數取小,有可能編程負數
cout << max(0, min(a[2] - 1, a[8])) << "\n";
cout << "Happy Birthday!\n";
}
return 0;
}
6.6181: Alice與閃電
這個一個比較復雜的循環題,我們可以將其分兩三輸出,前m/2行,中間行,后m/2行,前m/2行前面的空格分析下,為m-i個,*為i+1個,中間行全是是n個,然后依次類推。至於中間用空行隔開,我們可以用一個旗子來表示,剛開始沒有插旗子,不能輸出空行,執行一次就插上了旗子,當然是否要輸出空行要在插旗子之前。詳見代碼flag的操作。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
//定義旗子
int flag = 0;
while (cin >> n)
{
//插了旗子就要進行換行,第一次不會換行
if (flag)cout << "\n";
//插旗子
flag = 1;
//找到對應的行
int m = n / 2;
for (int i = 0; i < m; i++)
{
//輸出m-i個空格
for (int j = m; j > i; j--)
cout << " ";
//輸出i+1個星號
for (int j = 0; j <= i; j++)
cout << "*";
cout << "\n";
}
//輸出第m行
for (int i = 0; i < n; i++)
{
cout << "*";
}
cout << "\n";
//倒着輸出每一行
for (int i = m - 1; i >= 0; i--)
{
//輸出m-1個空格
for (int j = 0; j < m; j++)
cout << " ";
//輸出i+1個星號
for (int j = 0; j <= i; j++)
cout << "*";
cout << "\n";
}
}
return 0;
}
7.6180: Alice玩井棋
這是一個比較有趣的游戲,但是不同的思路實現起來難度可能不同,在這里推薦了一個比較簡單的實現,
1.橫或豎坐標均相同
2.在左上到右下的對角線上
3.在右上到左下對角線上
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x1, x2, x3, y1, y2, y3;
while (cin >> x1 >> y1)
{
cin >> x2 >> y2;
cin >> x3 >> y3;
int f = 0;
//成行或成列
if ((x1 == x2 && x2 == x3) || (y1 == y2 && y2 == y3))
f = 1;
//從左上到右下
if (x1 == y1 && x2 == y2 && x3 == y3)
f = 1;
//從左下到右上
if (x1 + y1 == 4 && x2 + y2 == 4 && x3 + y3 == 4)
f = 1;
if (f)
cout << "Win" << endl;
else
cout << "Continue" << endl;
}
return 0;
}
8.6174: Alice與甜甜圈
空圓柱體的體積,體積為底面積高,
圓環面積為(R*R-r*r)PI
注意這個題目給我們的數是實數
#include<bits/stdc++.h>
using namespace std;
int main()
{
//實數包括整數和小數,是double類型的
double R,r,h;
double PI = acos(-1);//3.1415926536
while(cin>>R>>r>>h)
{
//底面積乘高
double ans = PI*h*(R*R - r*r);
printf("%.2f\n",ans);
}
return 0;
}
9.6175: Alice買口罩
10個口罩一定會浪費掉,所以你買到y個口罩,買x個一次,次數為y/x
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x,y;
cin>>x>>y;
//輸出次數
cout<<y/x;
return 0;
}
10.6176: 武漢加油!中國加油!
簡單C++輸出,可以復制粘貼,盡量減少錯誤
#include <bits/stdc++.h>
using namespace std;
int main()
{
//記得復制粘貼,不要交錯語言
cout<<"Fighting, Wuhan! Stay strong, China!\n";
}
