1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
| #include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
const int maxn=1e4+4;
int t;
int n,m,k;
struct p{
int r,c,val;
p(){}
p(int _r,int _c,int _val):r(_r),c(_c),val(_val){}
friend bool operator<(const p& x, const p& y){
return x.c<y.c;
}
}ps[maxn];
vector<ll> solve_dp(const vector<p>& ms, int dest){
//ms[0]是开始位置,dest是结束位置
vector<ll> dp(ms.size(),inf);
vector<ll> dp2(ms.size(),inf);
dp2[0]=0;
//dp2数组时刻保证距离的增长,即到i的距离,它只有在刚进行过更新时才有可能是有效的dp值,否则会有溢出的距离值
dp[0]=(dest==-1?0:abs(ms[0].c-dest));
for(int i=1;i<ms.size();i++){
int len=ms[i].c-ms[i-1].c; //到达本次新加入元素的距离
for(int j=0;j<i;j++) //注意下标
dp2[j]+=len;
for(int j=i;j>0;j--)
dp2[j]=min(dp2[j],dp2[j-1]+ms[i].val); //尝试用新元素更新
for(int j=1;j<=i;j++){
ll tmp=dp2[j]+(dest==-1?0:abs(ms[i].c-dest)); //刚选取最后一个最优元素时更新成功
dp[j]=min(dp[j],tmp);
}
}
return dp;
}
vector<ll> merge(const vector<ll>& a,const vector<ll>& b){
vector<ll> c(a.size()+b.size()-1,inf);
for(int i=0;i<a.size();i++){
for(int j=0;j<b.size();j++){
c[i+j]=min(c[i+j],a[i]+b[j]);
}
}
return c;
}
ll ans[maxn];
int main(){
cin>>t;
while(t--){
scanf("%d%d%d",&n,&m,&k);
vector<int> disc;
disc.push_back(1); //必须考虑第一行
for(int i=1;i<=k;i++){
scanf("%d %d %d",&ps[i].r,&ps[i].c,&ps[i].val);
disc.push_back(ps[i].r);
}
sort(disc.begin(),disc.end());
int rows=unique(disc.begin(),disc.end())-disc.begin();
disc.erase(disc.begin()+rows,disc.end());
vector<p> lines[maxn];
for(int i=0;i<=rows;i++)
lines[i].clear();
for(int i=1;i<=k;i++){
int row=lower_bound(disc.begin(),disc.end(),ps[i].r)-disc.begin();
lines[row].push_back(ps[i]);
ans[i]=inf;
}
for(int i=0;i<rows;i++){
sort(lines[i].begin(),lines[i].end());
}
vector<p> curL=lines[0];
vector<ll> dp[2];
curL.insert(curL.begin(),p(1,1,0));
vector<ll> dp0=solve_dp(curL,-1);
dp[0]=solve_dp(curL,(m+1)/2);
for(int i=1;i<curL.size();i++)
ans[i]=min(ans[i],dp0[i]);
for(int i=1;i<rows;i++){
curL=lines[i];
p ept(disc[i],(m+1)/2,0);
vector<p>::iterator split=lower_bound(curL.begin(),curL.end(),ept);
vector<p> l=vector<p>(curL.begin(),split);
vector<p> r=vector<p>(split,curL.end());
l.push_back(ept);
r.insert(r.begin(),ept);
reverse(l.begin(),l.end());
vector<ll> dpl[2];
vector<ll> dpr[2];
dpl[0]=solve_dp(l,-1);
dpl[1]=solve_dp(l,(m+1)/2);
dpr[0]=solve_dp(r,-1);
dpr[1]=solve_dp(r,(m+1)/2);
vector<ll> g1,g2;
g1=merge(dpl[0],dpr[1]);
g2=merge(dpl[1],dpr[0]);
vector<ll> g(g1.size()); //本行不返回中点的dp值
for(int i=1;i<g.size();i++){
g[i]=min(g1[i],g2[i]);
//g[i]+=(disc[i]-disc[i-1]);
}
g=merge(dp[(i-1)&1],g); //g是当前最优解
dp[i&1]=merge(dp[(i-1)&1],merge(dpl[1],dpr[1]));
for(int j=0;j<g.size();j++){
dp[i&1][j]+=(disc[i]-disc[i-1]);
ans[j]=min(ans[j],g[j]+=(disc[i]-disc[i-1])); //只有在刚达到最优结果时才能更新成功
}
}
for(int i=1;i<=k;i++)
printf("%lld%c",ans[i],(i==k?'\n':' '));
}
return 0;
}
|