uvaoj384
本题一直让我WA的是 INF的设定,一定要大! 2^30 (1073741824)
输出格式要留心一些就可以啦,注意只输入一组答案是什么
比如:
1
5 1
输出是 (A1) 不是 A1
printf("Case %d: ",count++);
if(n == 1){printf("(A1)\n");continue;} //单独输出
dfs( 0 ,n);
print(0 , n);
printf("\n");
在给几组测试的数据
10
2 84
84 66
66 8
8 410
410 8
8 96
96 10
10 200
200 10
10 2
10
2 64
64 8
8 55
55 333
333 44
44 887
887 554
554 1
1 226
226 33
0
output
Case 1: (((A1 x A2) x A3) x (A4 x (A5 x (A6 x (A7 x (A8 x (A9 x A10)))))))
Case 2: ((A1 x (A2 x (A3 x (A4 x (A5 x (A6 x (A7 x A8))))))) x (A9 x A10))
记忆化搜索好想,注意好区间的控制就可以,要知道每一层的回退,都会得到一个区间内的链乘最小值,记录到
d[][]中,一定要理解d所存值的意义。
#include
#include
#define min(a,b) a0)return d[l][h];
int k,ans;
ans = INF;
for(k = l+1;k dfs(l,k) + dfs(k,h) + a[l]*a[k]*a[h])
{
ans = d[l][k] + d[k][h] + a[l]*a[k]*a[h]; //回退后的区间对应有最小值,已经存在d[][]了
vis[l][h] = k;
}
}
d[l][h]=ans;
return ans;
}
void print(int l ,int h)
{
if(h-l==1){ printf("A%d",l+1);return;}
int k = vis[l][h];
printf("(");
print(l,k);
printf(" x ");
print(k,h);
printf(")");
}
int main()
{
int n,i,j,count =1;
while(scanf("%d",&n))
{
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
if(n==0)break;
for(i = 0;i
数组递推
最有意思的就是二维数组了,它可以表示任意连续区间 i到 j (i表示该区间开始的位置,j表示该区间结尾的位置。一共占整个二维数组空间的上三角位置。
前提,先理解 二维数组 在这里的意义。
递推思路:
1.通过区间的大小开始递推,从长度为1 的区间开始推(从小区间推大区间),然后推到n 。这时, d表示区间大小的变量决定一层循环
2.区间的递推 需要有开始的位置,这时,表示行的 i 就表示开始的位置(上三角),决定一层循环
3. i的位置,d的大小,决定了 j(区间结束的位置)
4. k的枚举分割了,了 i 到 j 的区间。 dp[i][j] = min( dp[i][j] , d[i][k] + d[k+1][j] + w(i,j,k)) (每层的分割都建立在上一层分割的基础上,而上一层的分割已经确定了最小链乘值。
理解之后,写递推就方便多了。
以单个矩阵为基础的区间划分 (左闭右闭)
#include
#define INF 1<<30
int dp[20][20],path[20][20];
void print(int l ,int h)
{
if(h == l){ printf("A%d",l+1);return;} //不知道大家注意到没,这里的条件变了,由于这是以每一个矩阵为基础去划分区间
int k = path[l][h]; //上个记忆化搜索是以 把矩阵的每个元素x,y打到了一位数组上了,那么就是以元素为基础去划分区间
printf("(");
print(l,k);
printf(" x ");
print(k+1,h); //注意
printf(")");
}
int main()
{
int n,i,j,k,d,ans,count = 1;
int left[20],right[20];
while(scanf("%d",&n))
{
if(n ==0)break;
for(i =0;idp[i][k] + dp[k+1][j] + left[i]*right[k]*right[j])
{
dp[i][j] = dp[i][k] + dp[k+1][j] + left[i]*right[k]*right[j];
path[i][j] = k;
}
}
}
printf("Case %d: ",count++);
if(n == 1){printf("(A1)\n");continue;}
print(0 , n-1); //注意
printf("\n");
}
return 0;
}
在此,再给出 将元素打到一维数组上,以元素为基础的区间划分,输出函数又和写记忆化搜索是一样的了
(左闭右开)
#include
#include
#define INF 1<<30
int dp[20][20],path[20][20];
void print(int l ,int h)
{
if(h - l == 1){ printf("A%d",l+1);return;}
int k = path[l][h];
printf("(");
print(l,k);
printf(" x ");
print(k,h); //注意
printf(")");
}
int main()
{
int n,i,j,k,d,ans,count = 1;
int v[20];
while(scanf("%d",&n))
{
if(n ==0)break;
for(i =0;idp[i][k] + dp[k][j] + v[i]*v[k]*v[j])
{
dp[i][j] = dp[i][k] + dp[k][j] + v[i]*v[k]*v[j];
path[i][j] = k;
}
}
}
printf("Case %d: ",count++);
if(n == 1){printf("(A1)\n");continue;}
print(0 , n); //注意
printf("\n");
}
return 0;
}
以上代码,全部AC了,大胆的看吧(*^__^*) 。