这里说一说心得。当你看到一道题目的时候,如果这条思路走不通,那么快点换一个思路。
当时我一直在想如何用构图体现换路线,但是发现走不通。其实,如果采用区间DP,就能显示”换路线“的意思了。
还有,题目中如果给出的是m,n最好换成你看得懂的词语,不然容易打乱。
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int maxm = 30;
//max node
const int maxn = 550;
//max size
const int maxd = 130;
//max days
struct edge
{
int to;
int next;
int w;
};
struct node
{
int d;
int id;
friend bool operator<(node a,node b)
{
return (a.d>b.d);
}
};
class CShortestSolver
{
private:
int head[maxm];
edge e[maxn];
int cur;
priority_queue<node> q;
bool vis[maxm];
private:
void init(int source,int size);
public:
CShortestSolver();
void clear();
void addEdge(int from,int to,int weight);
int solve(int source,int size,int des);
};
CShortestSolver solver;
CShortestSolver::CShortestSolver()
{
memset(head,-1,sizeof head);
cur = 0;
};
void CShortestSolver::clear()
{
memset(head,-1,sizeof head);
cur = 0;
while (!q.empty()) q.pop();
memset(vis,false,sizeof vis);
}
void CShortestSolver::addEdge(int from,int to,int weight)
{
//cout << "Zulagen fra" << from << "fo" << to << endl;
e[cur].next = head[from];
e[cur].to = to;
e[cur].w = weight;
head[from] = cur;
cur++;
};
void CShortestSolver::init(int source,int size)
{
memset(vis,false,sizeof(vis));
node temp;
for (int i = 1;i <= size;++i)
{
if (i != source)
{
temp.d = 1000000000;
temp.id = i;
q.push(temp);
}
else
{
temp.d = 0;
temp.id = i;
q.push(temp);
}
}
}
int CShortestSolver::solve(int source,int size,int des)
{
init(source,size);
node temp;
int cnt = 1;
while (cnt <= size)
{
node top = q.top();
q.pop();
if (vis[top.id]) continue;
cnt++;
if (top.id == des) return top.d;
vis[top.id] = true;
int cur = head[top.id];
while (cur != -1)
{
temp.id = e[cur].to;
temp.d = top.d + e[cur].w;
q.push(temp);
cur = e[cur].next;
}
}
return -1;
}
int f[maxd][maxd];
struct edge2
{
int from,to,w;
};
edge2 data[maxn];
edge2 ban[maxn*5];
bool valid[maxm][maxd];
int dis[maxd][maxd];
bool judge(int from1,int to1,int from2,int to2)
{
if (to1 <= from2) return true;
if (from1 >= to2) return true;
return false;
}
int main(int argc,char * argv[])
{
int tagen,hafen,kes,e;
cin >> tagen >> hafen >> kes >> e;
for (int i = 0 ;i < e;++i)
{
cin >> data[i].from >> data[i].to >> data[i].w;
}
int d;
cin >> d;
CShortestSolver solver;
memset(valid,true,sizeof(valid));
for (int i = 0;i < d;++i)
{
cin >> ban[i].w >> ban[i].from >> ban[i].to;
for (int j = ban[i].from;j <= ban[i].to;++j) valid[ban[i].w][j] = false;
}
for (int i = 1; i <= tagen;++i)
{
bool konnen[maxm];
for (int j = 1;j <= hafen;++j) konnen[j] = valid[j][i];
for (int j = i;j <= tagen;++j)
{
solver.clear();
if (j != i) for (int k = 1;k <= hafen;++k) konnen[k] &= valid[k][j];
for (int k = 0;k < e;++k) if (konnen[data[k].from] && konnen[data[k].to])
{
solver.addEdge(data[k].from, data[k].to, data[k].w);
solver.addEdge(data[k].to, data[k].from, data[k].w);
}
dis[i][j] = solver.solve(1, hafen, hafen);
if (dis[i][j] != 1000000000) dis[i][j] *= (j-i+1);
}
}
for (int i = 1;i <= tagen;++i)
{
for (int j = i;j <= tagen;++j)f[i][j] = dis[i][j];
}
for (int i = 2;i <= tagen;++i)
{
for (int j = 1;j <= tagen-i+1;++j)
{
int k = i+j-1;
for (int l = j;l <= k;++l) if (f[j][l] + f[l+1][k] + kes < f[j][k]) f[j][k] = f[j][l] + f[l+1][k] + kes ;
}
}
cout << f[1][tagen] << endl;
return 0;
}