poj 1185
http://poj.org/problem?id=1185
/*Problem: 1185 User: ruan123Memory: 2128K Time: 266MSLanguage: G++ Result: Accepted说下dp方程:dp[i][j][k] 为第i行状态为Sj,第i-1行状态为Sk时前i行最多能放置的炮数。 */#include <stdio.h>#include <string.h>#include <stdlib.h>int dp[105][65][65];int s[105],map[105],cnt,c[100];void init(int m){ m = 1<<m; for(int i = 0; i < m; ++ i){ if(!(i&(i<<1)) && !(i&(i<<2))){ int sum = 0; int k = i; while(k){ sum += k&1; k /= 2; } c[cnt] = sum; s[cnt++] = i; } }}int main(){ int n,m,ans = 0; char str[100]; cnt = 0; scanf("%d%d",&n,&m); for(int i = 0; i < n; ++ i){ scanf("%s",str); for(int j = 0; str[j]; ++j ) if(str[j] == 'H') map[i] += (1 << j); } init(m); memset(dp,-1,sizeof(dp)); for(int i = 0; i < cnt; ++ i) if(!(map[0]&s[i])) dp[0][i][0] = c[i]; for(int i = 1; i < n; ++ i){ for(int j = 0; j < cnt; ++ j){ if(s[j]&map[i])continue;//有冲突 for(int k = 0; k < cnt; ++ k){ if(s[j]&s[k])continue;//有冲突 for(int l = 0; l < cnt; ++ l){ if(s[j]&s[l])continue;//有冲突 if(dp[i-1][k][l]<0)continue;//没有值 dp[i][j][k] = dp[i][j][k] > dp[i-1][k][l] + c[j] ? dp[i][j][k] : dp[i-1][k][l] + c[j]; } } } } for(int i = 0; i < cnt; ++ i) for(int j = 0; j < cnt; ++ j){ ans = dp[n-1][i][j] > ans? dp[n-1][i][j] : ans; } printf("%d\n",ans); return 0;}
A Tour Around Hangzhou
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1175
/**************************************************************
Problem: 1175
User: aigoruan
Language: C++
Result: Accepted
Time:520 ms
Memory:14680 kb
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1175
思路:dfs下的状态dp
****************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<vector>
using namespace std;
const int inf = 0xffffff;
int que[1000005],city[20],as[20][20];
int dis[10005],vis[10005];
int dp[16][1<<17];
vector<int>graph[10005];
vector<int>cost[10005];
int n,m,k,full;
void spfa(int s,int x)
{
int ts = 0,te = 1;
for(int i = 0; i < n; ++ i) dis[i] = inf;
memset(vis,0,sizeof(vis));
que[ts] = s;
dis[s] = 0;
while(ts<te){
int k = que[ts];
vis[k] = 0;
for(int i = 0; i < graph[k].size(); ++ i){
int t = graph[k][i];
int v = cost[k][i];
if( dis[t] > dis[k] + v ){
dis[t] = dis[k] + v;
if(!vis[t]){
que[te++] = t;
vis[t] = 1;
}
}
}ts++;
}
for(int i = 0; i <= k; ++ i)
as[x][i] = dis[city[i]];
}
int dfs(int p,int stat)
{
if(dp[p][stat] != -1) return dp[p][stat];
if(stat == full) return dp[p][stat] = as[p][0];
int ans = inf, tmp;
for(int i = 1; i <= k; ++ i){
if((stat&(1<<i)) == 0){
tmp = dfs(i,stat ^ (1 << i));//由stat状态出发,求出最优解
if( tmp + as[p][i] < ans )
ans = as[p][i] + tmp;
}
}
return dp[p][stat] = ans;
}
int main()
{
while(scanf("%d",&n)==1){
scanf("%d%d",&m,&k);
for(int i = 0; i < n; ++ i){ graph[i].clear(); cost[i].clear(); }
int a,b,c;
while(m--){
scanf("%d%d%d",&a,&b,&c);
graph[a].push_back(b);
cost[a].push_back(c);
graph[b].push_back(a);
cost[b].push_back(c);
}
for(int i = 1; i <= k; ++ i)scanf("%d",city+i);
scanf("%d",&city[0]);
for(int i = 0; i <= k; ++ i)spfa(city[i],i);
bool isok = true;
for(int i = 0; i <= k; ++ i)
for(int j = 0; j <= k; ++ j)
if( as[i][j] == inf ) isok = false;
if(!isok){
puts("What a pity");
}else{
full = (1<<(k+1))-2;
for(int i = 0; i <= k; ++ i)
for(int j = 0; j <= full; ++ j)
dp[i][j] = -1;
printf("%d\n",dfs(0,0));
}
}return 0;
}
(以上三题目都参考的网上代码,算是入门)
Painting A Board
http://poj.org/problem?id=1691
/*
Problem: 1691 User: ruan123
Memory: 168K Time: 0MS
Language: C++ Result: Accepted
Ps:预处理当前块能画色之前那些块必须画好色了;
当要画当前块时,先判断下前面的块是否已画好;
(同一思想,dfs应该可过)
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct nd{
int x1,y1,x2,y2,cl;
}as[20];
int s[20];
int vis[20];
int n;
bool cmp(struct nd a,struct nd b){
if(a.y1 == b.y1 )return a.x1 < b.x1;
return a.y1 < b.y1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0; i < n; ++ i)
scanf("%d %d %d %d %d",&as[i].y1,&as[i].x1,&as[i].y2,&as[i].x2,&as[i].cl);
sort(as,as+n,cmp);
memset(s,0,sizeof(s));
for(int i = 0; i < n; ++ i){
for(int j = 0; j < i; ++ j){
if(as[i].y1 == as[j].y2){
//预处理当前块能画色之前那些块必须画好色了
if((as[i].x1 <= as[j].x1 && as[i].x2 >= as[j].x1)||
(as[i].x1 >= as[j].x1 && as[i].x2 <= as[j].x2)){
s[i] += (1<<j);
}
}
}
}
int ans = 100;
for(int k = 0; k < n; ++ k){
if(as[k].y1)break;
int stat = 0;
int tmp = 0;
memset(vis,-1,sizeof(vis));
for(int i = -1; i < n; ++ i){
if(i==-1||vis[i]==-1){
int ii = i==-1?k:i;
stat += (1<<ii);
vis[ii] = 0;
++tmp;
for(int j = 0; j < n; ++ j)
if(vis[j]==-1){
//当要画当前块时,先判断下前面的块是否已画好
if((as[j].cl == as[ii].cl) && ((s[j]&stat) == s[j]) ){
stat += (1<<j);
vis[j] = 0;
}
}
}
}
if(ans > tmp) ans = tmp;
}
printf("%d\n",ans);
}return 0;
}
Rectangular Covering
http://poj.org/problem?id=2836
/*
Problem: 2836 User: ruan123
Memory: 424K Time: 172MS
Language: C++ Result: Accepted
只有15个点,每个点用二进制中的一位来表示
预处理,枚举n*(n-1)/2个矩形,每个矩形的有自己的状态(覆盖的点)和面积
状态转移方程
for(int i = 0; i < (1<<n); ++ i)
for(int j = 0; j < cnt; ++ j)
dp[k] = Min(dp[k],dp[i] + val[j]);
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int n,cnt;
int stat[300],val[300];
int x[20];
int y[20];
void getstat(int s,int t)
{
int k = (1<<(s-1))+(1<<(t-1));
for(int i = 1; i <= n; ++ i)
if((x[i]-x[s])*(x[t]-x[i])>=0 && (y[i]-y[s])*(y[t]-y[i])>=0)
k |= 1<<(i-1);
stat[cnt] = k;
int j = 1;
if(x[s]==x[t]) j = y[s] - y[t];
else if(y[s]==y[t]) j = x[s] - x[t];
else j = (x[s]-x[t])*(y[s]-y[t]);
if(j < 0)j *= -1;
val[cnt++]=j;
}
int dp[1<<16];
int Min(int x,int y)
{
return x > y ? y : x;
}
int main()
{
while(scanf("%d",&n)==1)
{
if(!n)break;
for(int i = 1; i <= n; ++ i) scanf("%d %d",x+i,y+i);
cnt = 0;
for(int i = 1; i <= n; ++ i)
for(int j = i+1; j <= n; ++ j) getstat(i,j);
memset(dp,-1,sizeof(dp));
dp[0] = 0;
for(int i = 0; i < (1<<n); ++ i){
if(dp[i]==-1) continue;
for(int j = 0; j < cnt; ++ j){
int k = stat[j] | i;
if(k == i)continue;//状态i与j无相交的
if(dp[k]==-1) dp[k] = dp[i] + val[j];
else dp[k] = Min(dp[k],dp[i] + val[j]);
}
}
printf("%d\n",dp[(1<<n)-1]);
}return 0;
}