小胖办证
Time Limit:10000MS Memory Limit:65536K
Total Submit:5 Accepted:1
Case Time Limit:1000MS
Description
描述 Description
xuzhenyi要办个签证。办证处是一座M层的大楼,1<=M<=100。
每层楼都有N个办公室,编号为1..N(1<=N<=500)。每个办公室有一个签证员。
签证需要让第M层的某个签证员盖章才有效。
每个签证员都要满足下面三个条件之一才会给xuzhenyi盖章:
1. 这个签证员在1楼
2. xuzhenyi的签证已经给这个签证员的正楼下(房间号相同)的签证员盖过章了。
3. xuzhenyi的签证已经给这个签证员的相邻房间(房间号相差1,楼层相同)的签证员盖过章了。
每个签证员盖章都要收取一定费用,这个费用不超过1000000000。
找出费用最小的盖章路线,使签证生效
Input
第1行两个整数M和N。
接下来M行每行N个整数,第i行第j个数表示第i层的第j个签证员收取的费用
Output
按顺序打出你经过的房间的编号,每行一个数。
如果有多条费用最小的路线,输出任意一条。
Sample Input
3 4
10 10 1 10
2 2 2 10
1 10 10 10
Sample Output
3
3
2
1
1
简单的 动态规划。。 用pre[]和now[]存放路线。
但是没注意题目的大小。错了两次。应该要用int64的
下面是AC代码:
#include<iostream> using namespace std; #define ll __int64 int a[110][550]; ll b[110][550]; ll dp[110][550]; int now[110][550]; int pre[110][550]; int max(int a,int b){ return a>b?a:b; } int min(int a,int b){ return a>b?b:a; } void print_ans(int a,int b){ if(a==1){ cout<<now[a][b]<<endl; return ; } else{ print_ans(a-1,pre[a][b]); int i,start=pre[a][b],end=now[a][b]; if(start<end) for(i=start;i<=end;i++) cout<<i<<endl; else for(i=start;i>=end;i--) cout<<i<<endl; // for(int i=min(pre[a][b],now[a][b]);i<=max(pre[a][b],now[a][b]);i++) // cout<<i<<endl; } } int main(){ int n,m,i,j,k; ll res; //cout<<res<<endl; cin>>m>>n; for(i=1;i<=m;i++) for(j=1;j<=n;j++){ cin>>a[i][j]; b[i][j]=b[i][j-1]+a[i][j]; } for(i=1;i<=n;i++){ dp[1][i]=a[1][i], now[1][i]=i; } for(i=2;i<=m;i++) for(j=1;j<=n;j++){ dp[i][j]=dp[i-1][j]+a[i][j]; now[i][j]=j; pre[i][j]=j; for(k=1;k<=n;k++){ if(k<j){ if(dp[i-1][k]+b[i][j]-b[i][k]+a[i][k]<dp[i][j]){ dp[i][j]=dp[i-1][k]+b[i][j]-b[i][k]+a[i][k]; pre[i][j]=k; } } else{ if(dp[i-1][k]+b[i][k]-b[i][j]+a[i][j]<dp[i][j]){ dp[i][j]=dp[i-1][k]+b[i][k]-b[i][j]+a[i][j]; pre[i][j]=k; } } } } int end=1; res=dp[m][1]; for(i=2;i<=n;i++) if(dp[m][i]<res){ end=i; res=dp[m][i]; } print_ans(m,end); // cout<<dp[4][1]<<" "<<dp[2][1]<<endl; return 0; }