题目链接——> P2294 [HNOI2005]狡猾的商人
写完看了一下题解区发现用区间DP的不多,也有一些缺陷,在此就来完善一番。
题目大致释意:若无法给出一组数满足给出的 mm 个条件,则输出 false ,反之则输出 true 。
给出数组 a[i][j]a[i][j] 表示区间 ii 到 jj 的区间和。初始值设为 inf 。
于是我们给出三重循环,第一重枚举每次区间长度,第二重枚举左端点, 第三重枚举左右端点之间的位置。 ii 表示左端点, jj 表示右端点, kk 表示区间长度, ll 表示左右端点之间的位置。我们可以从中知道 a[i][j]=a[i][l]+a[l+1][j]a[i][j]=a[i][l]+a[l+1][j] 的递推式。如果 a[i][j]a[i][j] 与已确定的 a[i][l] + a[l + 1][j]a[i][l]+a[l+1][j] 不同,则可直接退出。同时我们可以在一开始判重,若不一样,则可直接退出。
具体详见代码——>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 123456789//定义
using namespace std;
int w, n, m, a[105][105], p;
int main(){
scanf("%d",&w);
while(w--){
scanf("%d%d",&n,&m);
p = 1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) a[i][j] = inf;//别忘了赋初值哦~
for(int i = 1; i <= m; i++){
int x, y, z;
scanf("%d%d%d",&x,&y,&z);
if(a[x][y] == inf || a[x][y] == z)//从读入开始判断
a[x][y] = z;
else p = 0;
}
if(p)
for(int k = 1; k <= n; k++){
for(int i = 1; i + k <= n; i++){
int j = k + i;
for(int l = i; l < j; l++){//DP主体
if(a[i][l] != inf && a[l + 1][j] != inf){//若已确定两个子区间
if(a[i][j] == inf) a[i][j] = a[i][l] + a[l + 1][j];//未有则赋值,已有则比较
else if(a[i][j] != a[i][l] + a[l + 1][j]){
p = 0;
goto there;//若不同,直接退出
}
}
}
}
}
there:;
if(p) printf("true\n");
else printf("false\n");
}
return 0;
}
观察到 n < 100n<100 , w < 100w<100 , 足够我们跑了。不吸氧333ms足以满足需求。
撒花完结╰( ´・ω・)つ──☆✿✿✿