學校作業-Dp練習


題目


★Stringsobits01 串 
考慮排好序的 N(N<=31)位二進制數. 
你會發現,這很有趣.因爲他們是排列好的,而且包含所有可能的長度爲 N 且含有 1 的個數小於等於
L(L<=N)的數. 
你的任務是輸出第 I(1<=I<=長度爲 N 的二進制數的個數)大的,長度爲 N,且含有 1 的個數小於等
於 L 的那個二進制數. 
PROGRAM NAME: kimbits 
INPUT FORMAT
共一行,用空格分開的三個整數 N,L,I. 
SAMPLE INPUT (file kimbits.in) 
5 3 19 
OUTPUT FORMAT

共一行,輸出滿足條件的第 I 大的二進制數. 

SAMPLE OUTPUT (file kimbits.out) 
10011 


題解


這道題吧,我覺得就是一位一位試,如果當前填0,用組合數計算一下共有多少個數字,如果小於i的話,當前就填1,否則就填0,一直試下去就可以了。我猜它可以數位DP?沒仔細想QAQ


代碼


/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;

#define LL long long

inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;}

LL n,l,m;
int Ans[40];
LL Pow[32];
inline LL getC(int n,int m){
	LL Ans=1;
	if (n-m>m) m=n-m;
	for (int i=m+1;i<=n;i++) Ans*=i;
	for (int i=2;i<=n-m;i++) Ans/=i;
	return Ans;
}
inline LL getCS(int n,int m){
	LL Ans=1;
	for (int i=1;i<=m;i++) Ans+=getC(n,i);
	return Ans;
}
int main(){
	scanf("%lld%lld%lld",&n,&l,&m);
	for (int i=n;i>=2;i--){
		LL tmp=getCS(i-1,remin(i-1,(int)l));
		if (tmp<m){
			m-=tmp;
			Ans[i]=1;
			l-=1;
		}else{
			Ans[i]=0;
		}
	}
	Ans[1]=!(m==1);
	bool isOne=false;
	for (int i=n;i>=1;i--){
		isOne=isOne||Ans[i];
		if (isOne) printf("%d",Ans[i]);
	}
	printf("\n");
	return 0;
}


題目


★Raucous Rockers“破鑼搖滾”樂隊 
你剛剛繼承了流行的“破鑼搖滾”樂隊錄製的尚未發表的 N(1 <= N <= 20)首歌的版權.你打算從
中精選一些歌曲,發行 M(1 <= M <= 20)張 CD.每一張 CD 最多可以容納 T(1 <= T <= 20)分鐘的音
樂,一首歌不能分裝在兩張 CD 中. 
不巧你是一位古典音樂迷,不懂如何判定這些歌的藝術價值.於是你決定根據以下標準進行選擇: 
歌曲必須按照創作的時間順序在 CD 盤上出現. 選中的歌曲數目儘可能地多. 
PROGRAM NAME: rockers 
INPUT FORMAT
第一行: 三個整數:N, T, M. 
第二行: N 個整數,分別表示每首歌的長度,按創作時間順序排列. 
SAMPLE INPUT (file rockers.in) 
4 5 2 
4 3 4 2 
OUTPUT FORMAT
一個整數,表示可以裝進 M 張 CD 盤的樂曲的最大數目. 
SAMPLE OUTPUT (file rockers.out) 


題解


這道題目我調了好長時間,我自我檢討QAQ,因爲太困了【鬼信你啊!好吧,f[i][j]={a,b}表示前i個歌曲裝j首,最少需要a個光碟,並且那種情況下最後一張光碟剩餘b分鐘之間。這樣從f[i-1][j]和f[i-1][j-1]隨便轉移就好了!


代碼


/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;

#define LL long long

inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;}

int n,t,m;
int ti[25];
struct Node{
	int index;
	int left;
	Node(){index=left=2147483647;}
	Node(int a,int b){index=a;left=b;};
	void update(Node x){
		int i=x.index;
		int l=x.left;
		if (i<index){
			index=i;
			left=l;
		}else if (i==index && l<left){
			left=l;
		}
	}
	void update_new(Node x,int xt){
		update(Node(x.index+1,t-xt));
		if (x.left-xt>=0) update(Node(x.index,x.left-xt));
	}
};
Node f[25][25];

int main(){
	scanf("%d%d%d",&n,&t,&m);
	for (int i=1;i<=n;i++) scanf("%d",&ti[i]);
	f[0][0].index=0;
	f[0][0].left=t;
	int min=2147483647;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=i;j++){
			f[i][j].update(f[i-1][j]);
			f[i][j].update_new(f[i-1][j-1],ti[j]);
		}
	}
	int Ans=0;
	for (int i=1;i<=n;i++)if (f[n][i].index<=m) Ans=i;
	printf("%d\n",Ans);
	return 0;
}


題目


★Canada Tour 周遊加拿大 
你贏得了一場航空公司舉辦的比賽,獎品是一張加拿大環遊機票.旅行在這家航空公司開放的最西
邊的城市開始,然後一直自西向東旅行,直到你到達最東邊的城市,再由東向西返回,直到你回到開
始的城市.每個城市只能訪問一次,除了旅行開始的城市之外,這個城市必定要被訪問兩次(在旅行
的開始和結束).你不允許使用其他公司的航線或者用其他的交通工具. 
給出這個航空公司開放的城市的列表,和兩兩城市之間的直達航線列表.找出能夠訪問儘可能多的
城市的路線,這條路線必須滿足上述條件,也就是從列表中的第一個城市開始旅行,訪問到列表中最
後一個城市之後再返回第一個城市. 
PROGRAM NAME: tour 
INPUT FORMAT
Line 1: 航空公司開放的城市數 N 和將要列出的直達航線的數量 V.N 是一個不大於 100 的

正整數.V 是任意的正整數. 
Lines 2..N+1: 每行包括一個航空公司開放的城市名稱.城市名稱按照自西向東排列.不會出
現兩個城市在同一條經線上的情況.每個城市的名稱都是一個字符串,最多 15 字節,由拉丁字母表
上的字母組成;城市名稱中沒有空格. 
Lines N+2..N+2+V-1: 每行包括兩個城市名稱(由上面列表中的城市名稱組成),用一個空格分開.
這樣就表示兩個城市之間的直達雙程航線. 
SAMPLE INPUT (file tour.in) 
8 9 
Vancouver 
Yellowknife 
Edmonton 
Calgary 
Winnipeg 
Toronto 
Montreal 
Halifax 
Vancouver Edmonton 
Vancouver Calgary 
Calgary Winnipeg 
Winnipeg Toronto 
Toronto Halifax 
Montreal Halifax 
Edmonton Montreal 
Edmonton Yellowknife 
Edmonton Calgary 
OUTPUT FORMAT
Line 1: 按照最佳路線訪問的不同城市的數量 M.如果無法找到路線,輸出 1. 
SAMPLE OUTPUT (file tour.out) 

也就是: Vancouver, Edmonton, Montreal, Halifax, Toronto, Winnipeg, Calgary, 和 Vancouver 
(回到開始城市,但是不算在不同城市之內). 


題解


這裏我們反向返回的邊,就變成了求兩個不同路徑。我們使用f[i][j]表示兩個人一個到第i個城市,一個到第j個城市的經過城市數量。我們在轉移的時候時刻保證i<j這樣我們有一條k->j的邊一定可以保證沒有在f[i][k]中走過,因爲f[i][k]還沒有考慮j這個點。然後我們有對稱性可知,f[i][j]=f[j][i]就這樣愉快的一直推,最後找到最大的f[i][n]就可以了!


代碼


/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
using namespace std;

#define LL long long

inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;}

map<string,int> city;
bool g[105][105];
int f[105][105];
int n,m;
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		string tmp;
		cin>>tmp;
		city[tmp]=i;
	}
	for (int i=1;i<=m;i++){
		string tmp1,tmp2;
		cin>>tmp1>>tmp2;
		g[city[tmp1]][city[tmp2]]=g[city[tmp2]][city[tmp1]]=true;
	}
	f[1][1]=1;
	for (int i=1;i<=n;i++){
		for (int j=i+1;j<=n;j++){
			for (int k=1;k<j;k++){
				if (g[k][j] && f[i][k]>0 && f[i][k]+1>f[i][j]) f[i][j]=f[j][i]=f[i][k]+1;
			}
		}
	}
	int Ans=1;
	for (int i=1;i<=n;i++){
		if (g[i][n] && f[i][n]>Ans) Ans=f[i][n];
	}
	printf("%d\n",Ans);
	return 0;
}

P.S.今天的作業做得略慢啊!BZOJ還剩48次提交,用完它!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章