/*
标题不能太长,所以写这了
poj_2533_Longest Ordered Subsequence poj_1260_Pearls hdu_1025_Constructing Roads In JGShining's King hdu_1074_Doing Homework
*/
poj_2533_Longest Ordered Subsequence
http://poj.org/problem?id=2533
LIS 不解释 ==
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int n;
cin>>n;
int a[1010];
int dp[1010];
for (int i=0;i<n;i++){
cin>>a[i];
}
int ans=1;
for (int i=0;i<n;i++){
dp[i]=1;
for (int j=0;j<i;j++){
if(a[i]>a[j]){
dp[i]=max(dp[i],dp[j]+1);
}
}
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
}
poj_1260_Pearls
http://poj.org/problem?id=1260
有n种珍珠,价额越高,质量越好,购买时每种应付款(数量+10)*单价;
原计划n种珍珠,第i种买ai颗,价格pi;(价p i>p i-1)
现在需要求换种方案,使得购买的数量不变,且质量更好,总价更小,求总价。
价格更少的关键在于那个“+10”,
此外,替换珍珠是连续的一个段,如果第i+2种珍珠可以用来替换第i种,那么第i+1应该更便意。
so dp[i] = min ( dp[i] , dp[j] +(sum[i] - sum[j] + 10) * p[i] );
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=999999999;
struct Node {
int a,p;
}node[106];
bool cmp (Node a,Node b){
return a.p<b.p;
}
int main(){
int c;
cin>>c;
while (c--){
int n,sum=0;
int dp[106];
int s[106];
dp[0]=0;s[0]=0;
cin>>n;
for (int i=1;i<=n;i++){
cin>>node[i].a>>node[i].p;
sum+=(node[i].a+10)*node[i].p;
s[i]=s[i-1]+node[i].a;
}
sort(node,node+n,cmp);
for (int i=1;i<=n;i++){
dp[i]=INF;
for (int j=0;j<=i-1;j++){
dp[i]=min(dp[i],dp[j]+(s[i]-s[j]+10)*node[i].p);
}
// cout<<dp[i]<<" ";
}
cout<<dp[n]<<endl;
}
return 0;
}
hdu_1025_Constructing Roads In JGShining's King
http://acm.hdu.edu.cn/showproblem.php?pid=1025
平行线上有一些城市,一边是富饶的,一边是贫困的。没坐父老的城市拥有一种资源,对应着有一座贫困的城市缺少改资源。
现在The King 希望修通富饶城市和贫困城市之间的马路来帮助他们(资源的拥有和缺少必须对应),但为了防止交通事故,不允许两条道路相交叉。
问最多修多少道路。
以贫困城市为数组下标,富饶城市为数组元素的值,求 LIS 。
== 题目好坑,O(nlogn)的方法猜不会TLE,(copy自白书)而且,road和roads啊啊啊啊啊==
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
const int INF=999999999;
int dp[500050];
int main(){
int c(0);
char road[2][10]={"road","roads"};
while (scanf("%d",&n)!=EOF){
int a[500050];
for (int i=0;i<n;i++){
int x,y;
scanf ("%d%d",&x,&y);
a[x-1]=y;
}
fill (dp,dp+n,INF);
for (int i=0;i<n;i++){
*lower_bound(dp,dp+n,a[i])=a[i];
}
int ans=lower_bound(dp,dp+n,INF)-dp;;
printf ("Case %d:\nMy king, at most %d %s can be built.\n",++c,ans,road[ans!=1?1:0]);
}
return 0;
}
hdu_1074_Doing Homework
http://acm.hdu.edu.cn/showproblem.php?pid=1074
给出n份作业的截止时间第 D 天和需要花费时间 C 天,没迟交一天扣一分。
开这题好几天了,一直没思路,虽然知道是状压dp,知道今天中午吃饭的时候才来灵感,用一维的dp。T^T,一直在想二维的。
把n份作业的做与没做压缩成一个二进制的 int 。第i位表示第i份作业有没有做。
如果s表示做完的集合,那么他可以由 {s}-{j} V {j} 得到。
dp[s] = min( dp[s-(1<<j)] + s); ( s : 做第j份作业要罚的分,s = max( t[s] + Cs - Ds , 0 ) );
路径还原:fa 数组记录由状态 fa[ i ]得到状态 i ;还原是用位运算加递归;
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 999999999
struct Work {
string s;
int d,c;
}w[16];
struct Node{
int p,t;
};
int fa[1<<15+6];
Node dp[1<<15+6];
void findway (int a,int b){
int c=a-b;
int k=0;
while(c!=1){
c>>=1;
k++;
}
cout<<w[k].s<<endl;
}
void find (int f,int k){
if (f!=k){
find (fa[f],f);
findway(k,f);
}
}
int main(){
int c;
cin>>c;
while (c--){
int n;
scanf("%d",&n);
for (int i=0;i<n;i++){
cin>>w[i].s>>w[i].d>>w[i].c;
}
for (int i=0;i<(1<<n);i++){
dp[i].p=INF;dp[i].t=0;
fa[i]=i;
}
dp[0].p=0;
for (int i=1;i<(1<<n);i++){
for (int j=0;j<n;j++){
if (i&(1<<j)){
int s;
s=max(dp[i-(1<<j)].t+w[j].c-w[j].d,0);
if(dp[i].p>=dp[i-(1<<j)].p+s){
dp[i].p=dp[i-(1<<j)].p+s;
fa[i]=i-(1<<j);
}
dp[i].t=dp[i-(1<<j)].t+w[j].c;
}
}
}
printf ("%d\n",dp[(1<<n)-1]);
int k=(1<<n)-1;
find(fa[k],k);
}
return 0;
}
dp水我水的好欢快啊~啊。