貪欲(4)選択順序の問題

目次

1つは、問題を選択します

第二に、セットの選択

CSU 1012:プレステージ

CSU 1043:ケグモア

3、両端キューの選択

OpenJ_Bailian-3377ベストカウライン、ゴールド


1つは、問題を選択します

私が行ったいくつかの質問によると、選択の問題をセットの選択の問題と両端キューの選択の問題に分けました。

 

第二に、セットの選択

CSU 1012:プレステージ

トピック:

説明

よく見ていますか?

すべての素晴らしい手品は3つの行為で構成されています。最初の行為は誓約と呼ばれ、魔術師はあなたに普通の何かを見せますが、もちろん、そうではないでしょう。2番目の行為はターンと呼ばれます。魔術師は彼の普通の何かに異常な何かをさせます。さて、あなたが秘密を探しているなら、あなたはそれを見つけることができません。だからこそ、プレステージと呼ばれる第3幕があります。これは紆余曲折のある部分であり、人生はバランスのとれた状態にあり、今までに見たことのない衝撃的な何かを目にします。

LiLeiとHanMeimeiは魔術師であり、名声を発揮したいと考えています。だから彼らはマジックショーのために小道具を分ける必要があります。彼らは次の手順を決定しました:すべての小道具が選択されるまで、順番に小道具を1つずつ選択します。

LiLeiとHanMeimeiは、何を選択するかを決定する際に異なる戦略を持っています。選択に直面したとき、LiLeiは常に彼にとって最も価値のある小道具を選択します。同点の場合、彼は非常に思いやりがあり、ハン・メイメイにとって最も価値のないものを選びます。(LiLeiとHanMeimeiは良い友達なので、各小道具の他の場所がどれだけの価値があるかを正確に知っています。)

しかし、ハン・メイメイの戦略は、彼女自身の最終的な価値(彼女が選んだすべての小道具の合計値)を最大化することから成ります。彼女はまた非常に思いやりがあるので、複数の選択肢が同じ最適な結果につながる場合、彼女はLiLeiができるだけ多くの最終的な価値を持つことを好みます。

誰が最初に選択するかという結果が与えられます。LiLeiとHanMeimeiがすべての小道具を分割し終えた後、それぞれの小道具の合計値はどのくらいになりますか?

入力

最初の行の正の整数:テストケースの数、最大100。その後、テストケースごとに:

  • 整数nn1≤≤1,000)の1行 :小道具の数。

  • LiLeiの場合は「L」またはHanMeimeiの場合は「H」のいずれかの文字が付いた1行:最初に選択する人。

  • n それぞれliとhi(0≤li、hi≤1000)の2つの整数を持つ行:LiLeiとHanMeimeiがそれぞれi番目の小道具に割り当てる値。

出力

テストケースごとに、LiLeiが取得する値とHanMeimeiが取得する値の2つの整数を含む1行を出力します。両方の値は、それぞれの評価に従う必要があります。

サンプル入力

3
4
L
100 80
70 80
50 80
30 50
4
L
10 1
1 10
6 6
4 4
7
H
4 1
3 1
2 1
1 1
1 2
1 3
1 4

サンプル出力

170130 
14 16 
9 10

 

題名:

n個のアイテムがあり、LとHが交互にそれらをフェッチします

Lに対する各項目の値はv1であり、Hに対する値はv2です。

誰が最初に取るか、各アイテムv1v2の値を入力し、最終結果を出力します

Lの戦略は、毎回v1が最大のアイテムを取得することです。複数のアイテムがある場合は、v2が最小のアイテムを取得します。

Hの戦略は、最終的な合計値を可能な限り最大化することです。複数のオプションがある場合は、v1が最小のものを選択してください。

アイデア:

貪欲、まずLの戦略に従ってすべてのアイテムを並べ替えます

次に、Hは毎回最大のv2を持つアイテムを取得しますが、制限を満たすために、つまり、Lは常にこの順序で逆方向に取得されるため、Hは前のアイテムの半分しか取得できません。

この制限が満たされている限り、Hは最適解を得ることができます

コード:

#include<iostream>
#include<algorithm>
using namespace std;
 
int n;
char c;
bool visit[1001], ans[1001];
 
struct node
{
	int v1, v2;
}nod[1001];
 
bool cmp(node a, node b)
{
	if (a.v1 == b.v1)return a.v2 < b.v2;
	return a.v1 > b.v1;
}
 
int getmax()
{
	int max = 0, key = 0;
	for (int i = 1; i <= n; i++)
		if (!visit[i] && max <= nod[i].v2)max = nod[i].v2, key = i;
	return key;
}
 
bool ok(int k)
{
	int s = 0;
	for (int i = 1; i <= n; i++)
	{
		if (i == k || ans[i])s++;
		if (s > (i + (c == 'H'))/2)return false;
	}
	return true;
}
 
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n >> c;
		for (int i = 1; i <= n; i++)
		{
			cin >> nod[i].v1 >> nod[i].v2;
			visit[i] = false, ans[i] = false;
		}
		sort(nod + 1, nod + n + 1, cmp);
		int num = (n + (c == 'H')) / 2;
		visit[1] = (c == 'L');
		while (num)
		{
			int k = getmax();
			if (ok(k))ans[k] = true, visit[k] = true, num--;
			else for (int i = 1; i <= k; i++)visit[k] = true;
		}
		int s1 = 0, s2 = 0;
		for (int i = 1; i <= n; i++)
			if (ans[i])s2 += nod[i].v2; else s1 += nod[i].v1;
		cout << s1 << " " << s2 << endl;
	}
	return 0;
}

CSU 1043:ケグモア

説明

最近、人気のオンラインゲームLeague of Legends、dotaに似た5V5バトルゲーム、長距離攻撃ヒーローの1人であるAbyssal Kegmoreは非常に強力です。チームバトル中に立ってスプレーすると、世界を救うことができます...

ここで簡単なデータを計算します。ケグモアが反対側の5人によるスニークアタックに遭遇したと仮定すると、ケグモアは電話を切る前に敵を数回攻撃することができます。可能な限り高いダメージはどちらを殺すかを追求しません。それで、それが生み出すことができる最高の出力は何ですか?

入力

データの各グループの最初の行は正の整数n(0 <n <20)であり、Kegmoreが電話を切る前に実行できる攻撃の数を表し、次の5行は5つに与えることができるダメージを表します。敵。各行に2つの数字があり、最初の数字は敵の体力であり、2番目の数字は攻撃が生み出す可能性のあるダメージです。1回のダメージで敵の体力値が0未満の場合でも、今回のダメージ値はダメージ値に基づいて計算され、次回は死んだ敵を攻撃することはできません。敵の体力値は5500を超えず、攻撃が生み出す可能性のあるダメージは550を超えません。

出力

データの各セットは1行を出力し、Kegmoreが受ける可能性のある最大のダメージです。

サンプル入力

10
1000 300
5000 200
4000 500
3000 100
2000 550

サンプル出力

5200

コード:

#include<iostream>
#include<algorithm>
using namespace std;
 
struct node
{
	int sm, sh;
};
 
bool cmp(node a, node b)
{
	return a.sh > b.sh;
}
 
int main()
{
	int n;
	node nod[5];
	while (cin>>n)
	{
		for (int i = 0; i < 5; i++)cin >> nod[i].sm >> nod[i].sh;
		sort(nod, nod + 5, cmp);
		int ans = 0, t;
		for (int i = 0; n; i++)
		{
			t = (nod[i].sm - 1) / nod[i].sh + 1;
			if (t > n)t = n;
			n -= t, ans += t * nod[i].sh;
		}
		cout << ans << endl;
	}
	return 0;
}

 

3、両端キューの選択

OpenJ_Bailian-3377ベストカウライン、ゴールド

トピック:

FJは、毎年恒例の「ファーマーオブザイヤー」コンテストにN頭(1 <= N <= 30,000)の牛を連れて行こうとしています。このコンテストでは、すべての農家が牛を一列に並べ、審査員を追い越します。 

コンテストの主催者は今年、新しい登録スキームを採用しました。すべての牛の頭文字を表示される順序で登録するだけです(たとえば、FJがBessie、Sylvia、Doraをこの順序で使用する場合、彼はBSDを登録するだけです)。登録フェーズが終了した後、すべてのグループは、牛の名前のイニシャルの文字列に従って、辞書式順序(つまり、アルファベット順)の昇順で判断されます。 

FJは今年とても忙しく、急いで農場に戻らなければならないので、できるだけ早く判断されたいと思っています。彼は、登録する前に、すでに並んでいる牛を再配置することにしました。 

FJは、競合する牛の新しいラインの場所をマークします。次に、元のライン(残り)の最初または最後の牛を新しいラインの最後に繰り返し送信することにより、古いラインから新しいラインに牛をマーシャリングします。彼が終了すると、FJはこの新しい順序で登録のために彼の牛を連れて行きます。 

牛の最初の順序を前提として、この方法で作成できるイニシャルの最小辞書式文字列を決定します。入力* 1行目:単一の整数:N 

* 2行目。N+ 1:i + 1行目には1つのイニシャル( '元の行のi番目の位置にある牛のA '..' Z ')出力彼が作成できる最小の辞書式文字列。すべての行(おそらく最後の行を除く)には、改行に80頭の牛のイニシャル(「A」..「Z」)が含まれています。サンプル入力

6 
A 
C 
D 
B 
C 
B

サンプル出力

ABCBCD

 

質問の意味は非常に単純です。一連の数字が与えられた場合、毎回両端で1文字を取り出して、取得できる最小の辞書式文字列を見つけます。

ただ貪欲になりなさい。

コード:

#include<iostream>
using namespace std;
 
int main()
{
	int n;
	cin >> n;
	char s[30001];
	for (int i = 1; i <= n; i++)cin >> s[i];
	int left = 1, right = n, l, r;
	n = 0;
	while (left <= right)
	{
		l = left, r = right;
		while (s[l] == s[r] && l < r - 1)l++, r--;
		if (s[l] < s[r])cout << s[left++];
		else cout << s[right--];
		n++;
		if (n % 80 == 0)cout << endl;
	}
	return 0;
}

 

おすすめ

転載: blog.csdn.net/nameofcsdn/article/details/112753012