[kuangbin帶你飛]專題十二 基礎DP1 題解+總結

kuangbin帶你飛:點擊進入新世界node

文章目錄

1.Max Sum Plus Plus

原題連接:傳送門ios

2.Ignatius and the Princess IV

原題連接:傳送門c++

思路:hash存儲(感受和dp沒啥關係啊。。)數組

#include<bits/stdc++.h>
using namespace std;
map<int, int>mp; int n, t;
int main() {
    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false); cin.tie(0);
    while (cin >> n) {
        mp.clear();
        for (int i = 0; i < n; ++i) { cin >> t; mp[t]++; }
        for (auto &p : mp) {
            if (p.second >= (n + 1) / 2) { cout << p.first << endl; break; }
        }
    }
}

3.Monkey and Banana

原題連接:傳送門promise

解析:對於所給的磚塊能夠有6種組合(即:長寬高打亂)因此最終的 $ index = 6 * n$spa

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000;
struct node {
    int l, r, w;//長寬高
}a[maxn];

int n, r, w, l;

bool cmp(node &a, node &b) {
    if (a.l == b.l)return a.r < b.r;
    return a.l < b.l;
}

int dp[maxn];

int main() {
    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false); cin.tie(0);
    int Case = 1;
    while (cin >> n && n) {
        int index = 1;
        for (int i = 0; i < n; ++i) {
            cin >> l >> r >> w;
            a[index].l = l, a[index].r = r, a[index++].w = w;
            a[index].l = r, a[index].r = l, a[index++].w = w;
            a[index].l = w, a[index].r = r, a[index++].w = l;
            a[index].l = l, a[index].r = w, a[index++].w = r;
            a[index].l = r, a[index].r = w, a[index++].w = l;
            a[index].l = w, a[index].r = l, a[index++].w = r;
        }
        sort(a + 1, a + index + 1,cmp);//根據長寬排序
        memset(dp, 0,sizeof dp);
        int ans = 0;
        for(int i = 1;i <= index;++i)
            for (int j = 1; j <= index; ++j) {
                if (a[i].r < a[j].r && a[i].l < a[j].l)
                    dp[j] = max(dp[j], dp[i] + a[j].w), ans = max(ans, dp[j]);
            }
        cout << "Case " << Case++ << ": maximum height = " << ans << endl;
    }
}

4.Doing Homework (狀態壓縮DP)

HDU - 1074.net

解析:code

先大體說說狀態壓縮,假設有三門做業a,b,c
那麼,abc都作完即111,111可由101,110,011任意一個來獲得。而101能夠從100或者001來獲得,這就是狀態壓縮dp的一個基本的狀態轉移。排序

#include<bits/stdc++.h>
using namespace std;
const int N = 16;
struct Node
{
    char str[109];
    int want, need;
}node[N];

struct DP
{
    int now, sum, next, pos;
}dp[1 << N];

void put_ans(int x)
{
    if (dp[x].next != -1)
    {
        put_ans(dp[x].next);
        printf("%s\n", node[dp[x].pos].str);
    }
}

int main()
{
    freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%s%d%d", node[i].str, &node[i].want, &node[i].need);
        dp[0].now = dp[0].sum = 0;
        dp[0].next = dp[0].pos = -1;
        int m = (1 << n) - 1;
        for (int i = 1; i <= m; i++)
        {
            dp[i].sum = 0x3f3f3f3f;
            for (int j = 0; j < n; j++)
            {
                if ((1 << j) & i)
                {
                    int k = i - (1 << j);
                    int v = dp[k].now + node[j].need - node[j].want;
                    v = max(v, 0);
                    if (dp[i].sum >= dp[k].sum + v)
                    {
                        dp[i].sum = dp[k].sum + v;
                        dp[i].now = dp[k].now + node[j].need;
                        dp[i].next = k;
                        dp[i].pos = j;
                    }
                }
            }
        }
        printf("%d\n", dp[m].sum);
        put_ans(m);
    }
    return 0;
}

5.Super Jumping! Jumping! Jumping!

HDU - 1087ci

解析:注意題目是嚴格上升子序列並非連續上升子序列(致使我寫錯了轉移方程2333)

#include<bits/stdc++.h>
using namespace std;

#define ms(a,b) (a,b,sizeof a)

const int maxn = 1e3 + 10;
int dp[maxn], a[maxn];
int n;

int main() {
    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false); cin.tie(0);
    while (cin >> n && n) {
        ms(dp, 0);
        for (int i = 0; i < n; ++i)
            cin >> a[i], dp[i] = a[i];

        int ans = 0;

        for (int i = 0; i < n; ++i)
        {
            for (int j = i + 1; j < n; ++j)
            {
            	if (a[j] > a[i])
                    dp[j] = max(dp[j], dp[i] + a[j]);
            }
            ans = max(ans, dp[i]);
        }
        cout << ans << endl;
    }
}

一樣是LIS模板題:最少攔截系統:傳送門

6.Piggy-Bank

HDU - 1114

每種硬幣的數量都不限制,所以是個徹底揹包。初始化dp數組時需注意,由於求的最小,且題目的意思是剛好裝滿,因此dp數組初始化爲INF,但dp[0] = 0,意爲此時只有容量爲0 的揹包能夠在什麼也不裝且價值爲0 的狀況下被「剛好裝滿」,其它容量的揹包均沒有合法的解,屬於未定義的狀態(揹包九講)

#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
const int inf = 0x3f3f3f3f;
int dp[N], v[N], w[N];
int n, t, e, f;
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> t; while (t--) {
		cin >> e >> f;
		int W = f - e;
		cin >> n;
		for (int i = 1; i <= n; ++i)cin >> v[i] >> w[i];
		memset(dp, 0x3f, sizeof dp);	
		dp[0] = 0;
		for (int i = 1; i <= n; ++i) 
			for (int j = w[i]; j <= W; ++j) 
				dp[j] = min(dp[j], dp[j - w[i]] + v[i]);
		if(dp[W] == inf )printf("This is impossible.\n");
		else printf("The minimum amount of money in the piggy-bank is %d.\n", dp[W]);
	}
}

7.免費餡餅 (數塔 + 逆向DP)

HDU - 1176

思路:

若是把時間軸當作行數,每一個點在這個時間上得到的餅數當作列數,那麼a[i][j]表示在時間爲i時j點得到的餅,若是把圖畫出來就能夠發現這實際上是一道數塔題。
由於要處理相鄰兩邊,下標爲0的時候很差處理,因此把位置+1;
既然是數塔題,那麼顯而易見:

$ dp[i][j] = max({dp[i + 1][j - 1],dp[i + 1][j], dp[i + 1][j + 1]}) + a[i][j];$

這道題再升級一下就是加上高度的。POJ 1661Help Jimmy(逆向DP Or 記憶化搜索 Or 最短路徑)

#include<bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof a);
const int maxn = 1e5 + 50;
int t, x, y;
int a[maxn][15], dp[maxn][15];
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	while (cin >> t && t) {
		ms(dp, 0);
		ms(a, 0);
		int e = 0;
		for (int i = 0; i < t; ++i) { cin >> x >> y; a[y][++x]++; e = max(e, y); }
		for (int i = e; i >= 0; i--)
			for (int j = 1; j <= 11; j++)
				dp[i][j] = max({dp[i + 1][j - 1],dp[i + 1][j], dp[i + 1][j + 1]}) + a[i][j];
		cout << dp[0][6] << endl;
	}
}

8.Tickets

HDU - 1260

思路:

  1. 只能兩我的一塊兒買票,那麼遞推式很容易推出來:
  2. dp[i]=min(dp[i-1]+a[i] , dp[j-2]+b[i])
  3. 此處爲單獨買,和前一我的的買的較大值
  4. dp[n]爲答案 。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2010;
int a[maxn], b[maxn], dp[maxn];
int n, m, r, t = 0;
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	while (cin>>t) {
		while (t--) {
			cin >> n;
			for (int i = 1; i <= n; ++i)cin >> a[i];
			for (int i = 2; i <= n; ++i)cin >> b[i];
			dp[1] = a[1];
			for (int i = 2; i <= n; ++i)dp[i] = min(dp[i - 1] + a[i], dp[i - 2] + b[i]);	
			int h = 8, mi = 0, sec = 0;
			sec += dp[n];
			mi += sec / 60 % 60;
			h += sec / 3600;
			sec %= 60;
			printf("%02d:%02d:%02d ", h, mi, sec);
			if (h >= 12) printf("pm\n");
			else printf("am\n");
		}
	}
}

9.FatMouse's Speed

HDU - 1160

#include<bits/stdc++.h>
using namespace std;
struct Mouse
{
    int id;
    int speed;
    int weight;
    int pre;
    int dp;
} mouse[10010];

int cmp(Mouse a, Mouse b)
{
    if (a.weight == b.weight)
    {
        return a.speed > b.speed;
    }
    return a.weight < b.weight;
}
int dfs(int p)
{
    //printf("@%d %d\n",p,mouse[p].pre);
    if (p == -1) return 0;
    dfs(mouse[p].pre);
    printf("%d\n", mouse[p].id);
    return 0;
}
int main()
{
    int i = 0;
    while (~scanf("%d%d", &mouse[i].weight, &mouse[i].speed))
    {
        mouse[i].id = i + 1;
        mouse[i].pre = -1;
        mouse[i].dp = 1;
        i++;
    }
    sort(mouse, mouse + i, cmp);
    int n = i;
    mouse[0].dp = 1;
    int ans = 1;
    int p = 0;
    for (int i = 1; i < n; i++)
    {
        for (int j = 0; j < i; j++)
        {
            if (mouse[i].weight > mouse[j].weight && mouse[i].speed < mouse[j].speed)
            {
                if (mouse[j].dp + 1 > mouse[i].dp)
                {
                    mouse[i].dp = mouse[j].dp + 1;
                    mouse[i].pre = j;
                }
            }
        }
        if (mouse[i].dp > ans)
        {
            ans = mouse[i].dp;
            p = i;
        }
    }
    /*
    for(int i=0;i<n;i++)
    {
        printf("id:%d w:%d s:%d pre:%d dp:%d\n",mouse[i].id,mouse[i].weight,mouse[i].speed,mouse[i].pre,mouse[i].dp);
    }*/
    printf("%d\n", ans);
    dfs(p);
    return 0;
}

10.Jury Compromise

POJ - 1015

11.FatMouse and Cheese

HDU - 1078

思路:

  1. dp[i]平常表示前i個數的最大價值。
  2. 這題主要是把數據處理一下,把結束時間加上r,而後記得把結構體排序。
  3. 那麼就轉化成一維的最大子序列和了。
  4. dp[i]=max(dp[i],dp[k]+a[j].w) when a[k].r<=a[i].l&&l>k
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
int dp[maxn][maxn], a[maxn][maxn];
int nx[] = { 0,1,0,-1 };
int ny[] = { 1,0,-1,0 };
int n, m, r, t = 1;
int dfs(int x, int y) {
	if (dp[x][y]) return dp[x][y];
	int mx = 0;
	for (int i = 1; i <= m; ++i) {
		for (int j = 0; j < 4; ++j) {
			int xx = x + nx[j] * i, yy = y + ny[j] * i;
			if (a[x][y] < a[xx][yy] && xx>0 && yy > 0 && xx <= n && yy <= n)
				mx = max(dfs(xx, yy), mx);
		}
	}
	return dp[x][y] = a[x][y] + mx;
}
int main() {
	//freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	while (cin >> n >> m && n != -1 &&m != -1) {
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= n; ++j)
				cin >> a[i][j];
		memset(dp, 0, sizeof dp);
		cout << dfs(1, 1) << endl;
	}
}

12.Phalanx

HDU - 2859

思路:

  1. 最大對稱子矩陣,左下角到右上角爲對稱軸。
  2. 枚舉每個點,若是相同,把行數x向上擴展,列數y相右擴展。
  3. \(dp[i][j]=min(dp[i-1][j+1],i-x-1)+1 \quad when\quad a[i][j+1]==a[i-1][j]\)
#include<bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof a);
const int N = 1010;
char a[N][N];
int dp[N][N];
int n;
int main() {
	freopen("in.txt","r",stdin);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	while (cin >> n && n) {
		ms(dp, 0); 
		int ans = 1;
		for (int i = 1; i <= n; ++i)for (int j = 1; j <= n; ++j)cin >> a[i][j];
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++) {
				dp[i][j] = 1;
				int x = i, y = j;
				while (a[i][y] == a[x][j])x--, y++;
				if(a[i][j + 1] == a[i - 1][j])
					dp[i][j] = min(dp[i - 1][j + 1], i - x - 1) + 1;
				ans = max(ans, dp[i][j]);
			}
		cout << ans << endl;
	}
}
相關文章
相關標籤/搜索