1. 程式人生 > 其它 >AtCoder Beginner Contest 204 補題記錄

AtCoder Beginner Contest 204 補題記錄

寄了,vp一場只寫出了兩道題,我是彩筆

C - Tour

題目大意:給定n個點m條單向邊,求總共有多少個點對能夠滿足(i,j)從i到j

解題思路:在寫題目的時候想到用環去寫,只要找到環的數量就可以計算,但是苦於找不到所有環,由於給的資料範圍非常小(只有2000),那麼在n ^ 2的時間複雜度的演算法都能夠被接受,那麼我們遍歷一遍全圖是O(n)的時間,n個點都遍歷一遍就是n ^ 2,那麼我們就可以通過暴力直接去寫

反思:考慮到時間複雜度,沒考慮到暴力做法,想法太過侷限

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3 + 10;
vector<vector<int> > G;
int vis[maxn];
int T,n,m;
int u,v;
ll ans = 0;
void BFS(int s)
{
	queue<int> q;
	q.push(s);
	vis[s] = 1;
	while(!q.empty())
	{
		int x = q.front();
		q.pop();
		for(int h:G[x])
		{
			if(vis[h] == 0)
			{
				vis[h] = 1;
				q.push(h);
			}
		}
	}
}
void DFS(int s)
{
	if(vis[s]) return;
	vis[s] = 1;
	for(auto h:G[s])
	{
		if(vis[h] == 0)
		{
			DFS(h);
		}
	}
	return;
}
void solve()
{
	scanf("%d %d",&n,&m);
	G.resize(maxn);
	for(int i = 1;i <= m;++i)
	{
		scanf("%d %d",&u,&v);
		G[u].emplace_back(v);
	}
	for(int i = 1;i <= n;++i)
	{
		for(int j = 1;j <= n;++j) vis[j] = 0;
		DFS(i);
		for(int j = 1;j <= n;++j)
		{
			if(vis[j]) ans++;
		}
	}
	printf("%lld\n",ans);
}
int main()
{
	T = 1;
	while(T--)
	{
		solve();
	}
	return 0;
}

D - Cooking

解題思路:給定n個物品需要烹飪,我們有2個鍋,求我們需要烹飪最短時間

解題思路:在做題過程中,想到其實物品如何擺放是對最終結果沒有影響的,無論最終如何都只有A鍋和B鍋加起來是全部的時間,那麼我們假設A鍋時間比較大,那麼對於A鍋來說,我們要儘可能找到A的大於所有烹飪時間一半的最小值。但是如何去找呢?

想法一:二分,我們可以通過二分去列舉時間,但是如何去線性的表示並且修改相對應的遞增遞減呢?

因此二分的想法被我們給否決了,但是對於任意一個時刻對於任意一個物品,我們如果需要把物品放入,這個時間是取決於之前的時間的,分析時間複雜度我們可以發現ai的值並不是很大,因此我們可以想到如果有一個東西是儲存之前i - 1個物品所需要的時間,那麼對於第i 個時間來說,我們我們就可以進行計算了

那麼對於A鍋來說,設出動態規劃轉移方程式dp[i][j],i表示第i個物品,j表示可能需要的時間,那麼對於這一時刻如果我們這裡有東西的,我們可以選擇把物品放在b鍋,則dp[i + 1][j] = 1;我們也可以選擇把東西放回A鍋,那麼可以得出dp[i + 1][j + a[i]] = 1

需要注意的是我們的邊界點是dp[0][0] = 1,邊界迴圈是從0 - > n - 1

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
bool dp[110][maxn];
int T,n,m;
int a[110];
int sum = 0;
void solve()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)
	{
		scanf("%d",&a[i]);
		sum += a[i];
	}
	dp[0][0] = 1;
	for(int i = 0;i < n;++i)
	{
		for(int j = 0;j <= sum;++j)
		{
			if(dp[i][j])
			{
				dp[i + 1][j] = 1;
				dp[i + 1][j + a[i + 1]] = 1;
			}
		}
	}
	for(int i = (sum + 1) / 2;i <= sum;++i)
	{
		if(dp[n][i])
		{
			printf("%d\n",i);
			break;
		}
	}
}
int main()
{
	solve();
	return 0;
}