解法1:
n!枚举路径
解法2:
状压dp
将已访问过的点和当前访问的点为状态进行dp
#include
#include
#include
using namespace std;
const int N=21,M=1<<21;
const int INF=1<<30;
int dist[N][N];
int d[M][N];
int n;
int dp(int S,int u){
if(d[S][u]!=-1)
return d[S][u];
if(S==(1<1)
return 0;
d[S][u]=INF;
for(int v=0;vif(dist[u][v]!=-1&&!((1<1<return d[S][u];
}
int main()
{
scanf("%d",&n);
for(int i=0;ifor(int j=0;jscanf("%d",&dist[i][j]);
int ans=INF;
memset(d,-1,sizeof d);
for(int i=0;i1<printf("%d",ans);
}
#include
#include
#include
using namespace std;
const int N=21,M=1<<21;
const int INF=1<<30;
int d[M][N];
int n,map1[N][N],ans,s;
int main()
{
scanf("%d",&n);
ans=0x3f3f3f3f;
for(int i=0;ifor(int j=0;jscanf("%d",&map1[i][j]);
memset(d,0x7f,sizeof d);
for(int i=0;i1<0;
for(int s=1;s<=(1<1;s++)
for(int j=0;jfor(int k=0;kif((s&(1<1<1<for(int j=0;j1<1][j]);
printf("%d",ans);
}
题目大意:给出一些城市和连接它们的双向边,无重边,无自环,通过道路需要车票,你有n张车票,每张车票都有一个值,只能使用一次,通过i号道路使用j号车票所用时间是di/tj。询问从城市a到b的最短时间,无解输出Impossible。n<=10,点数<=30,边数<=2000
定义状态为:剩余车票集合为S,现在在城市u
d[S′][v]=d[S][u]+dist[u][v]/h[i](i|S′=S) d [ S ′ ] [ v ] = d [ S ] [ u ] + d i s t [ u ] [ v ] / h [ i ] ( i | S ′ = S )
下面给出递推的实现
#include
#include
#include
using namespace std;
const int N=35,M=2005,T=10;
const int INF=1<<30;
struct node{
int v,w,nxt;
}edge[M];
int head[N],mcnt;
void add_edge(int u,int v,int w){
mcnt++;
edge[mcnt].v=v;
edge[mcnt].w=w;
edge[mcnt].nxt=head[u];
head[u]=mcnt;
}
double d[1<int t[T];
int n,m,p;
int from,to;
int main()
{
while(1){
scanf("%d%d%d%d%d",&p,&n,&m,&from,&to);
if(n==0&&m==0)
return 0;
from--,to--;
for(int i=0;iscanf("%d",&t[i]);
memset(head,0,sizeof head);
mcnt=0;
for(int i=0;iint u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u-1,v-1,w);
add_edge(v-1,u-1,w);
}
for(int i=0;i<1<for(int j=0;j1<1][from]=0;
double ans=INF;
for(int S=(1<
1;S>=0;S--){
ans=min(ans,d[S][to]);
for(int u=0;ufor(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v,w=edge[i].w;
for(int j=0;jif((1<1<1<1.0/t[j]);
}
}
}
if(ans==INF)
printf("Impossible\n");
else
printf("%lf\n",ans);
}
}
N,M<=15
其实呢,如果只要求求出一种方案,我们可以跑网络流
由于是1×2的砖块,所以其实我们只需要知道本行和上行的信息即可,所以状态压缩dp+滚动数组即可(直接开是开不下的)
题意:
Farmer John 有N头牛,M个篮球场,每头牛有若干个想去的篮球场,一个篮球场只能容纳一头牛(话说一头牛怎么打篮球),求满足所有牛需求的分配方案的个数,保证不超过10000000
N,M<=20,4s,64MB
dp(S,i)表示分配前i头牛,剩余球场集合为S的方案数
转移方程呢一是比较显然,二是表述起来很麻烦,就不写了
直接开是开不下的,需要滚动数组
代码
#include
#include
#include
using namespace std;
const int N=21,M=1005,T=21;
const int INF=1<<30;
struct node{
int v,nxt;
}edge[M];
int head[N],mcnt;
void add_edge(int u,int v){
mcnt++;
edge[mcnt].v=v;
edge[mcnt].nxt=head[u];
head[u]=mcnt;
}
int d[2][1<int t[T];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int p;
scanf("%d",&p);
for(int j=1;j<=p;j++){
int num;
scanf("%d",&num);
num--;
add_edge(i,num);
}
}
int ans=0;
int *now=d[0],*nxt=d[1];
for(int i=head[1];i;i=edge[i].nxt){
int v=edge[i].v;
now[((1<1)-(1<1;
}
for(int u=2;u<=n;u++){
for(int S=1;S<=(1<1;S++)
if(now[S])
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if((1<1<for(int S=0;S<(1<0;
}
for(int S=0;S<(1<printf("%d\n",ans);
}
Farmer John 有n*m块地,其中一些地荒掉了不能种玉米。玉米是一种傲娇的植物,种在相邻的地里会导致不孕不育。求所有种法数对模100000000。
n,m<=12
基本上就是和例题3是一样的,数据范围略小一点,这次就可以不用滚动数组了(你要用没人拦你)
#include
long long map[15][15];
long long d[15][10000];
long long mod=100000000;
long long n,m;
void dp(long long line,long long x,long long z,long long last,long long lastd){
if(x==m+1){
d[line][z]=(d[line][z]+lastd)%mod;
return ;
}
dp(line,x+1,z*2,last,lastd);
if(!(z&1)&&map[line][x]&&!(last&(1<<(m-x)))){
dp(line,x+1,z*2+1,last,lastd);
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=n;i++)
for(long long j=1;j<=m;j++)
scanf("%lld",&map[i][j]);
dp(1,1,0,0,1);
for(long long i=2;i<=n;i++){
for(long long j=0;j<=(1<1;j++){
if(!d[i-1][j])
continue ;
dp(i,1,0,j,d[i-1][j]);
}
}
long long ans=0;
for(long long i=0;i<=(1<1;i++){
ans=(ans+d[n][i])%mod;
}
printf("%lld",ans);
}
题意:平面上有N个点,现在要用一些矩形(各边都在格线上)来覆盖它们,每个矩形至少覆盖2个点,求最少的矩形总面积
n<=15
预处理将n个点两两组合形成n * (n-1) / 2个矩形
d(S)表示点集为S时的最小面积
题意 :给出N个字符串,寻找一个字符串使得这N个字符串都是它的子串。输出最短的满足要求的串,如果有多个最短,输出字典序最小的
len<=100
n<=15
5s
预处理把j号串拼在i号串前面所增加的长度
(如aab拼在bca前增加长度为2)
d(S,i)表示目前答案串包含集合为S,最前面的是i号串
题意:N个城市间有m条单向路,分别从a到b,可以在c处交P路费(只能预交,不能赊账),也可以直接交R路费。无法到达输出impossible
n<=10
d(u,S)表示走到u节点,已经走过的点集为S
cost=((1<
代码
#include
#include
#include
#include
#include
using namespace std;
struct node{
int v,c,cost1,cost2;
}p;
vector edge[20];
int d[20][5000],n;
bool vis[20];
queue<int> q;
void spfa(){
vis[1]=1;
memset(d,-1,sizeof d);
d[1][2]=0;
q.push(1);
while(!q.empty()){
int x=q.front();
vis[x]=0;
q.pop();
for(int i=1;i<=(1<if(d[x][i]==-1)
continue ;
for(int j=0;jint v=edge[x][j].v,c=edge[x][j].c,cost1=edge[x][j].cost1,cost2=edge[x][j].cost2;
int cost=cost2;
if(i&(1<cost1)
cost=cost1;
if(d[v][i|(1<1||d[x][i]+cost1<1<if(!vis[v]){
vis[v]=1;
q.push(v);}
}
}
}
}
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u;
scanf("%d",&u);
scanf("%d%d%d%d",&p.v,&p.c,&p.cost1,&p.cost2);
edge[u].push_back(p);
}
spfa();
int ans=1<<30;
for(int i=1;i<=(1<<(n+1));i++){
if(d[n][i]!=-1&&d[n][i]if(ans==1<<30)
printf("impossible");
else
printf("%d",ans);
}
参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。
小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。
小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。
在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。
新开发一条道路的代价是: L*K
L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋)
请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代价最小,并输出这个最小值
对于 20% 的数据: 保证输入是一棵树,1≤n≤8 , v≤5000 且所有的 v 都相等。
对于 40% 的数据: 1≤n≤8,0≤m≤1000 , v≤5000 且所有的 v 都相等。
对于 70% 的数据: 1≤n≤8,0≤m≤1000,v≤5000
对于 100% 的数据: 1≤n≤12,0≤m≤1000 , v≤500000
首先,很容易发现打通后的道路一定是一棵树,并且,若以起点为根并令其深度为0,则题目中的 K 即为这条路所连向的点的深度。
状态:dp[i][S] 表示考虑到树的第i层,前i层已选的点的集合为S(二进制状压)的最小代价。:
转移:已知dp[i][S]时,可枚举所有由不在S中的点构成的集合作为第i+1层,则状态转移为
dp[i][S]→dp[i+1][S|S′]+=(i+1)×Σ min{G[a][b]|a∈S,b∈S′,S∩S′=∅}
简单一点,就是
dp[i][S]→dp[i+1][S|S′]+=(i+1)×sval[S′][S]}
其中sval[A][B]表示集合A到集合B的最短距离,即集合A中所有点到集合B的最短距离之和。可以先预处理出每个点到每个集合的最短距离pval[i][S](也就是点i到集合S中所有点的距离的最小值),然后用pval[i][B]更新sval[A][B]。
边界条件:枚举根节点,设为root,则dp[0][1<<(root−1)]=0
此部分来源:http://blog.csdn.net/phantomagony/article/details/78702573