Contest1075 动规专题测试
T1:MZOJ1348: 公交换乘
思路
很显然,设计f i表示在i节点时的最小值
如何转移?f i可以由f i-1,f i-2,f i-3……转移过来,所以
son从1~n
code如下:
/* NAME:EPSILON
WAY: DP
LANG:C++
TIME:7:56
*/
#include <bits/stdc++.h>
using namespace std;
int final;
int f[250],cost[250];
int read()
{
char ch=getchar();int x=0;
while(ch<'0' || ch>'9')ch=getchar();
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
void readdata()
{
for(int i=1;i<=10;i++)cost[i]=read();
final=read();
}
void init()
{
freopen("A.in","r",stdin);
}
void work()
{
memset(f,0x7f7f,sizeof(f));
f[0]=0;f[1]=cost[1];
for(int i=1;i<=10;i++)
for(int j=0;j+i<=200;j++)
{
if (f[j+i]>f[j]+cost[i]) f[j+i]=f[j]+cost[i];
}
printf("%d",f[final]);
}
int main()
{
init();
readdata();
work();
return 0;
}
T2:1349: 数字矩形
思路
每一个各自是由上,右,左推而来的,令f ij表示i行j列的最小值
注意几个小细节(就是一个ans=INT_MAX害得失了50分 )
递推顺序及方程:
code:
/* NAME:EPSILON
WAY: DP
LANG:C++
TIME:8:40
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m;
int mapp[maxn][maxn];
int f[maxn][maxn];
int read()
{
char ch=getchar();int x=0;
while(ch<'0' || ch>'9')ch=getchar();
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
void readdata()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
mapp[i][j]=read();
}
void init()
{
freopen("B.in","r",stdin);
}
void work()
{
for(int i=1;i<=m;i++)f[0][i]=0;
for(int i=1;i<=n;i++)//每一行
{
for(int j=1;j<=m;j++) f[i][j]=f[i-1][j]+mapp[i][j];//边界,下
for(int j=2;j<=m;j++)f[i][j]=min(f[i][j],f[i][j-1]+mapp[i][j]);//左
for(int j=m-1;j>=1;j--)f[i][j]=min(f[i][j],f[i][j+1]+mapp[i][j]);
int ans=INT_MAX;
for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
printf("%d",ans);
}
int main()
{
init();
readdata();
work();
return 0;
}
重头戏:MZOJ 1350: 排列 (SCOI2007)
状压DP
思路
至此,算法框架已经大致出来:
code
#include <bits/stdc++.h>
using namespace std;
int T,mod,l,ans,sum,r,x;
char s[15];
int f[15];
int dp[5005][1005];
void init()
{
freopen("MZOJ1350.in","r",stdin);
}
void work()
{
ans=dp[(1<<l)-1][0];
for(int i=0;i<10;i++)
{
sum=0;
for(int j=0;j<l;j++)
{
if(i==f[j])sum++;
}
r=1;
for(int j=1;j<=sum;j++)
{
r=r*j;
}
ans=ans/r;
}
printf("%d\n",ans);
}
void readdata()
{
scanf("%d",&T);
while(T--)
{
scanf("%s%d",s,&mod);
l=strlen(s);
for(int i=0;i<l;i++)
{
f[i]=s[i]-'0';
}
for(int i=0;i<(1<<l);i++)
for(int k=0;k<mod;k++)
dp[i][k]=0;
dp[0][0]=1;
////////////////////////////边界处理/////////////////////////////
////////////////////////////状压动归/////////////////////////////
for(int i=0;i<(1<<l);i++)
{
for(int k=0;k<mod;k++)
{
if(dp[i][k])//如果可行
{
for(int j=0;j<l;j++)
{
if((i&(1<<j))==0)
{
dp[i|(1<<j)][(k*10+f[j])%mod]+=dp[i][k];
}
}
}
}
}
work();
}
}
int main()
{
init();
readdata();
return 0;
}