[kuangbin 너를 데리고 날아간다] 주제 12 기초 DP1 문제풀이 + 요약

12389 단어
kuangbin 너를 데리고 날아: 클릭하여 신세계로

문서 목록


카탈로그
  • 기사 목록
  • 1.Max Sum Plus Plus
  • 2.Ignatius and the Princess IV
  • 3.Monkey and Banana
  • 4.Doing Homework(상태 압축 DP)
  • 5.Super Jumping! Jumping! Jumping!
  • 6.Piggy-Bank
  • 7.무료 파이(수탑+역방향 DP)
  • 8.Tickets
  • 9.FatMouse's Speed
  • 10.Jury Compromise
  • 11.FatMouse and Cheese
  • 12.Phalanx


  • 1.Max Sum Plus Plus


    전송문

    2.Ignatius and the Princess IV


    전송문
    사고방식:hash메모리(dp와 아무 상관이 없는 것 같은데...)
    #include
    using namespace std;
    mapmp; 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


    전송문
    해석: 주어진 벽돌에 대해 6가지 조합(즉, 길이와 너비, 혼란)이 있을 수 있기 때문에 최종 $index = 6 * n$
    #include
    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
    해결:
    먼저 대체적으로 상태 압축을 말하고 세 개의 숙제가 a, b, c가 있다고 가정하면 abc가 모두 하면 11111111은 10110011 임의로 얻을 수 있다.101은 100이나 001에서 얻을 수 있는데 이것이 바로 상태 압축 dp의 기본적인 상태 이동이다.
    #include
    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
    ", 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
    ", dp[m].sum); put_ans(m); } return 0; }

    5.Super Jumping! Jumping! Jumping!


    HDU - 1087
    해석: 주의 제목은 엄격한 상승자 서열이지 연속 상승자 서열이 아니다(내가 전이방정식 2333을 잘못 썼다)
    #include
    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인 상황에서'적당히 채워진다'는 뜻이다. 다른 용량의 가방은 모두 합법적인 해석이 없고 정의되지 않은 상태에 속한다(가방 9강)
    #include
    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.
    "); else printf("The minimum amount of money in the piggy-bank is %d.
    ", 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
    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
    아이디어:
  • 두 사람만 표를 살 수 있다면 추첨식은 쉽게 추측할 수 있다.
  • dp[i]=min(dp[i-1]+a[i] , dp[j-2]+b[i])
  • 이곳은 단독 구매로 전 사람과 비교적 큰 값
  • 을 샀다
  • dp[n]가 답입니다.
  • #include
    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
    "); else printf("am
    "); } } }

    9.FatMouse's Speed


    HDU - 1160
    #include
    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
    ",p,mouse[p].pre); if (p == -1) return 0; dfs(mouse[p].pre); printf("%d
    ", 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

    10.Jury Compromise


    POJ - 1015

    11.FatMouse and Cheese


    HDU - 1078
    아이디어:
  • dp[i]는 일상적으로 전 i개수의 최대 가치를 나타낸다.
  • 이 문제는 주로 데이터를 처리하고 끝 시간에 r를 추가한 다음에 구조체를 정렬하는 것을 기억한다.
  • 그러면 1차원의 가장 큰 서열과
  • dp[i]=max(dp[i],dp[k]+a[j].w) when a[k].r<=a[i].l&&l>k
  • #include
    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
    아이디어:
  • 최대 대칭 서브 행렬로 왼쪽 아래에서 오른쪽 상단은 대칭축이다.
  • 모든 점을 매거하고 같으면 행수 x를 위로 확장하고 열수 y를 오른쪽으로 확장한다.
  • \(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
    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;
    	}
    }
    

    좋은 웹페이지 즐겨찾기