#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string.h>
#include<cmath>
#include<string>
using namespace std;
//跪在题意理解和算法选择。
/*************************
题意非常复杂,一旦理解错了就没法做对。这里梳理一下:
1.有一个自行车管理站,为起点0。
其他各点上都有一定数量的自行车。
每个站点最多能有cmax辆车。
2.报告一个错误站点sp。
3.从管理站出发,找一条最短路径到达sp。
若选择该路径,则要把经过的所有站点调整为cmax/2。
如果身上自行车不够,就从管理站运来一些自行车。
如果有多余,就放在身上带到下一站。
当达到终点sp后,需要把多余的带回来。
4.要求先满足路径最短
再满足 带出自行车数量最少
最后满足带回自行车数量最少
*************************/
/************************
求解要点:
1.当试图使用dijstra求解时,先去画图,判断
是!否!满!足!贪!心!条!件!
即画2条路,合并到同一节点,判断是否当前最优,则后续一定最优。
这一题中,当sent数量最少时,无法保证后续sent最少
因为sent的值与身上back和后续节点所需有关。
故需要预测后续路径,故不可使用dijksra。
2.此时应该用dfs暴力求解。
每当找到一个可行解,修改当前最优信息。
剪枝:若当前搜索肯定比最优信息差,则返回。
优化:用vector来存边,而不是用矩阵。
************************/
/***********************
笔记:
dfs时,不要遗漏起点的vis=0
*********************/
#define M 550
#define INF 0xfffff
int c[M],dis[M][M];
int vis[M],pre[M];
int endp;
int cmax;
struct R
{
int e;
int l;
};
vector<R> road[M];
int sendmin,backmin,lmin;
vector<int> ansp;
void dfs(int p,int len,int send,int back)
{
if(len > lmin)
return ;
else if(len==lmin)
{
if(send > sendmin)
return ;
else if(send == sendmin)
{
if(back >= backmin)
return ;
}
}
//printf("p=%d,len=%d,send=%d,back=%d\n",p,len,send,back);
if(p==endp)
{
lmin=len;
sendmin=send;
backmin=back;
ansp.clear();
int pp=p;
while(pp!=-1)
{
ansp.push_back(pp);
pp=pre[pp];
}
return ;
}
int i,e,l;
int flen=len,fback=back,fsend=send;
for(i=0;i<road[p].size();i++)
{
e=road[p][i].e;
l=road[p][i].l;
if(vis[e]==1)
continue;
len += l;
back+=c[e]-cmax/2;
if(back<0)
{
send += (-1)*back;
back=0;
}
vis[e]=1;
pre[e]=p;
dfs(e,len,send,back);
vis[e]=0;
send=fsend;
back=fback;
len=flen;
}
}
int main()
{
int n,sp,m;
int i,j;
scanf("%d%d%d%d",&cmax,&n,&sp,&m);
endp=sp;
c[0]=0;
for(i=1;i<=n;i++)
scanf("%d",&c[i]);
int len,s1,s2;;
R Road;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&s1,&s2,&len);
Road.e=s2;
Road.l=len;
road[s1].push_back(Road);
Road.e=s1;
road[s2].push_back(Road);
}
pre[0]=-1;
memset(vis,0,sizeof(vis));
lmin=sendmin=backmin=INF;
vis[0]=1;//容易遗漏起点的vis
dfs(0,0,0,0);
printf("%d ",sendmin);
for(i=ansp.size()-1;i>=0;i--)
{
if(i!=0)
printf("%d->",ansp[i]);
else
printf("%d ",ansp[i]);
}
printf("%d\n",backmin);
return 0;
}
*************************/
二刷时的代码:1A
*************************/
/***********************
笔记:
*********************/
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<queue>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
using namespace std;
#define M 550
#define INF 0x7ffffff
int c[M];
vector<int> nextc[M];
int dis[M][M];
int vis[M];
int cmax, End;
int best_backc,best_len,best_takec;
vector<int> ans, best_ans;
void dfs(int s, int len, int nowc, int takec){
int i, e;
int Nowc = nowc, Takec = takec;
//printf("s= %d, len=%d, nowc=%d, takec=%d\n",s,len,nowc,takec);
if(len > best_len )
return ;
else if(len == best_len){
if(takec > best_takec)
return;
}
if(s == End){
if(len == best_len && takec == best_takec){
if(nowc < best_backc)
best_backc = nowc;
else return;
}else{
best_len = len;
best_takec = takec;
best_backc = nowc;
}
best_ans = ans;
return ;
}
for(i = 0;i < nextc[s].size(); i++){
e = nextc[s][i];
nowc = Nowc;
takec = Takec;
if(vis[e])
continue;
vis[e] = 1;
if(c[e] > cmax/2)
nowc += c[e] - cmax/2;
else if(c[e] < cmax/2){
nowc -= cmax/2 - c[e];
if(nowc < 0){
takec += nowc*(-1);
nowc = 0;
}
}
ans.push_back(e);
dfs(e, len + dis[s][e], nowc, takec);
vis[e] = 0;
ans.pop_back();
}
}
int main(){
int n, m, i,a ,b, len;
scanf("%d%d%d%d",&cmax, &n, &End, &m);
for(i = 1;i <= n; i++){
scanf("%d", &c[i]);
for(int j =0;j<n;j++){
if(i != j)
dis[i][j] = dis[j][i] = INF;
else dis[i][j] = 0;
}
}
c[0] = 0;
for(i = 0;i < m; i++){
scanf("%d%d%d",&a, &b, &len);
nextc[a].push_back(b);
nextc[b].push_back(a);
dis[a][b] = dis[b][a] = len;
}
memset(vis,0,sizeof(vis));
best_len = best_takec = best_backc = INF;
ans.push_back(0);
vis[0] = 1;
dfs(0, 0, 0, 0);
printf("%d ", best_takec);
for(i = 0;i < best_ans.size();i++)
if(i!=0)
printf("->%d", best_ans[i]);
else printf("%d", best_ans[i]);
cout<<" "<<best_backc<<endl;
return 0;
}