这是一个坑特别多而且值得深思的题
最短路嘛,一看就是dij,这里用一个数组存一下每一次的pre
pre定义是vector<int> pre[520]
这个题一个很需要注意的地方就是,它一共是N+1个点啊!!!!!
void dij(){
d[0]=0;
for (int i = 0; i <= N; ++i) {
int u=-1,MIN=INF;
for (int j = 0; j <= N ; ++j) {
if(vis[j]==0 && d[j]<MIN){
u=j;
MIN=d[j];
}
}
if(u==-1) return ;
vis[u]=1;
//cout<<"u1:"<<u<<endl;
for (int j = 0; j <= N ; ++j) {
if(vis[j]==0 && G[u][j]!=INF){
if(d[j]>d[u]+G[u][j]){
d[j]=d[u]+G[u][j];
pre[j].clear();
pre[j].push_back(u);
//cout<<"u2:"<<u<<endl;
}
else if(d[j]==d[u]+G[u][j]){
pre[j].push_back(u);
//cout<<"u3:"<<u<<endl;
}
}
}
}
}
然后对你的pre数组进行DFS
到叶节点(即v=0
)就计算一波need 和 remain
这个题不可以一边跑一边算的(可能受一些题的影响我会这么干)因为它后面的remain是不可以用在前面的节点,所以只能从前面跑一波。
然后正常记录你所需要的
这个题其实相当于三个标尺。在need一样的时候比较remain也很重要。
void DFS(int v){
if(v==0){//叶子节点
//这个地方的操作要注意,必须是从0开始跑一遍
//因为它必须要从头跑一遍啊
int need=0,remain=0;
int si=temp.size();
for (int i = si-1; i >= 0 ; --i) {
int id=temp[i];
//cout<<"id"<<id<<endl;
if(weight[id]>0){
remain+=weight[id];
}
else{
if(remain>abs(weight[id])){
remain-=abs(weight[id]);
}
else{
need+=abs(weight[id])-remain;
remain=0;
}
}
}
if(need<minNeed){
minNeed=need;
minRemain=remain;
ans=temp;
}
else if(need==minNeed && remain<minRemain){
minRemain=remain;
ans=temp;
}
//temp.pop_back();
return ;
}
if(!pre[v].empty()) {
int len=pre[v].size();
for (int i = 0; i < len ; ++i) {
temp.push_back(pre[v][i]);
// cout<<"pre"<<pre[v][i]<<endl;
DFS(pre[v][i]);
temp.pop_back();
}
}
}
然后涉及我自己的一些问题的话,就是说temp第一下没有把末尾那个点弄进去导致改了一小会,在DFS前先把sp搞数组里还是很有必要的
然后自己写的init函数,在N,M还没输入的时候就开始用了。。。
注意顺序啊喂!
感谢一下dl的样例:
10 2 2 2
2 10
0 1 1
1 2 1
3 0->1->2 5
10 3 3 3
11 0 10
0 1 1
1 2 1
2 3 1
0 0->1->2->3 6
10 4 4 5
6 7 5 0
0 1 1
0 2 1
1 3 1
2 3 1
3 4 1
3 0->2->3->4 0
10 4 4 4
6 0 11 0
0 1 1
1 2 1
2 3 1
3 4 1
4 0->1->2->3->4 1
10 4 4 8
0 11 3 0
0 1 2
0 2 3
0 3 2
1 2 1
2 3 1
1 4 2
2 4 1
3 4 2
0 0->2->4 1
10 6 6 8
8 9 4 6 7 2
0 1 1
0 2 1
1 3 1
2 3 1
3 4 1
3 5 2
4 6 1
5 6 1
0 0->1->3->4->6 0
写给自己:瓶颈期会过去,继续加油哇!
喔忘记贴代码咯:
#include<vector>
#include<iostream>
#include <algorithm>
#include <cmath>
#include<map>
#include <queue>
#include <stack>
#include<string.h>
using namespace std;
const int INF=100000;
int Cmax,N,sp,M;
int minNeed=INF,minRemain=INF;
int G[503][503];
int weight[503];
int vis[503]={0};
int d[503];
int w[503]={0};
vector<int> pre[502];
void init(){
for (int i = 0; i <= N ; ++i) {
for (int j = 0; j <= N ; ++j) {
if(i!=j){
G[i][j]=INF;
}
}
}
for (int i = 0; i <= N; ++i) {
d[i]=INF;
}
}
void dij(){
d[0]=0;
for (int i = 0; i <= N; ++i) {
int u=-1,MIN=INF;
for (int j = 0; j <= N ; ++j) {
if(vis[j]==0 && d[j]<MIN){
u=j;
MIN=d[j];
}
}
if(u==-1) return ;
vis[u]=1;
//cout<<"u1:"<<u<<endl;
for (int j = 0; j <= N ; ++j) {
if(vis[j]==0 && G[u][j]!=INF){
if(d[j]>d[u]+G[u][j]){
d[j]=d[u]+G[u][j];
pre[j].clear();
pre[j].push_back(u);
//cout<<"u2:"<<u<<endl;
}
else if(d[j]==d[u]+G[u][j]){
pre[j].push_back(u);
//cout<<"u3:"<<u<<endl;
}
}
}
}
}
vector<int> temp;
vector<int> ans;
void DFS(int v){
if(v==0){//叶子节点
//这个地方的操作要注意,必须是从0开始跑一遍
//因为它必须要从头跑一遍啊
int need=0,remain=0;
int si=temp.size();
for (int i = si-1; i >= 0 ; --i) {
int id=temp[i];
//cout<<"id"<<id<<endl;
if(weight[id]>0){
remain+=weight[id];
}
else{
if(remain>abs(weight[id])){
remain-=abs(weight[id]);
}
else{
need+=abs(weight[id])-remain;
remain=0;
}
}
}
if(need<minNeed){
minNeed=need;
minRemain=remain;
ans=temp;
}
else if(need==minNeed && remain<minRemain){
minRemain=remain;
ans=temp;
}
//temp.pop_back();
return ;
}
if(!pre[v].empty()) {
int len=pre[v].size();
for (int i = 0; i < len ; ++i) {
temp.push_back(pre[v][i]);
// cout<<"pre"<<pre[v][i]<<endl;
DFS(pre[v][i]);
temp.pop_back();
}
}
}
int main(){
cin>>Cmax>>N>>sp>>M;
init();
for (int i = 1; i <= N; ++i) {
cin>>weight[i];
weight[i]-=Cmax/2;
}
for (int i = 0; i < M; ++i) {
int u,v, l;
cin>>u>>v>>l;
G[u][v]=l;
G[v][u]=l;
// cout<<"G[v][u]:"<<G[u][v]<<endl;
}
dij();
//cout<<G[0][2]<<G[1][2]<<endl;
temp.push_back(sp);
DFS(sp);
cout<<minNeed<<" ";
int len=ans.size();
for (int i = len-1; i >= 0 ; --i) {
cout<<ans[i];
if(i!=0){
cout<<"->";
}
}
cout<<" "<<minRemain<<endl;
}