http://www.patest.cn/contests/pat-a-practise/1003
深入研究
本题适用dij+dfs,其中dij用来找出所有的最佳路径,而dfs根据第2,3,4...标出算出答案
首先用dij算法,根据各边权值算出最短路径,并用vector <int>pre [max]记住每条最短路径的前驱结点
注意点
1.pre初始化时,每个pre[i]存放i本身,这是为了后面dfs找到递归出口
for(int i=0;i<n;i++){
pre[i].push_back(i);
}
2.有优于权值的边出现时,要清空pre,因为原来记录的那些已经不是最佳了,而对于权值相等,则要记录在pre中
if(cost[u]>cost[newp]+c || cost[u]==-1){
pre[u].clear();
cost[u]=cost[newp]+c;
pre[u].push_back(newp);
}else if(cost[u]==cost[newp]+c){
pre[u].push_back(newp);
}
完整dij
void dij(int x){
//方便后面dfs
for(int i=0;i<n;i++){
pre[i].push_back(i);
}
int newp=x;
vis[newp]=1;
cost[newp]=0;
for(int i=0;i<n-1;i++){
for(int j=0;j<adj[newp].size();j++){
int u=adj[newp][j].next;
int c=adj[newp][j].wei;
if(vis[u]==0){
if(cost[u]>cost[newp]+c || cost[u]==-1){
pre[u].clear();
cost[u]=cost[newp]+c;
pre[u].push_back(newp);
}else if(cost[u]==cost[newp]+c){
pre[u].push_back(newp);
}
}
}
int min=123123123;
for(int j=0;j<n;j++){
if(cost[j]!=-1 && vis[j]==0){
if(cost[j]<min){
min=cost[j];
newp=j;
}
}
}
vis[newp]=1;
}
}
dfs中有path和tmppath两种vector
path用来记录最终的path,即答案
tmppath用来记录本次的dfs得到的路径,其本质就是一个栈,相当于把dfs节点入栈,遍历结束后,出栈
但注意的是最后的出口,叶子节点无法出入栈,则对叶子节点操作时应加入出入栈过程
此过程的另一个意思就是无向图的dfs遍历可以得到拓扑排序或逆拓扑排序
dfs的出口就是访问的元素为起点,在出口时判断是否为最佳路径,计算此时tmppath的value,若更优,更新maxx和path
if(v==c1){
ans++;
//入栈
tmppath.push_back(v);
int tmp=0;//当前路径的点权
for(int i=tmppath.size()-1;i>=0;i--){
int a=tmppath[i];
tmp+=val[a];
}
if(tmp>maxx){
maxx=tmp;
//vector直接赋值
path=tmppath;
}
//刚刚加入节点要删除,出栈
tmppath.pop_back();
return;
}
dfs的递归式将访问节点入栈,dfs该节点,访问完成后弹出
//入栈
tmppath.push_back(v);
for(int i=0;i<pre[v].size();i++){
dfs(pre[v][i],ans,maxx);
}
//出栈
tmppath.pop_back();
vector <int> path;
vector <int> tmppath;
void dfs(int v,int &ans,int &maxx){
if(v==c1){
ans++;
//也自己节点单独入栈
tmppath.push_back(v);
//当前路径的点权
int tmp=0;
for(int i=tmppath.size()-1;i>=0;i--){
int a=tmppath[i];
tmp+=val[a];
}
//判断是否最优
if(tmp>maxx){
maxx=tmp;
//vector直接赋值
path=tmppath;
}
//叶子节点单独出栈
tmppath.pop_back();
return;
}
//入栈
tmppath.push_back(v);
for(int i=0;i<pre[v].size();i++){
dfs(pre[v][i],ans,maxx);
}
//出栈
tmppath.pop_back();
}
综上,此求优dfs与普通dfs完全不同
求优dfs的目的是将所有可能的起点到终点的路径全部访问,这样才能求优,依据是pre中的元素是否全部访问过,体现在for循环中
普通dfs只是求一条路径,即找到一条起点到终点的路径即可,不需要知道全部路径,无重复访问的过程,故用vis来判断是否完成dfs
因此普通dfs是无法完成求优过程的
//传入终点
int ans[MAX];
int flag[MAX];
int maxx=0;
这种dfs用vis来标记是否访问过,不记录访问路径,会出错,
因为多条路径时,存在边重合,而vis已经为1,无法再次访问
int dfs(int x,int &num,int value){
flag[x]=1;
value+=val[x];
for(int i=0;i<pre[x].size();i++){
int u=pre[x][i];
if(u==x){
num++;
if(maxx<value){
maxx=value;
}
}else if(flag[u]==0){
dfs(u,num,value);
}
}
return maxx;
}
完整代码
#include <cstdio>
#include <vector>
using namespace std;
#define MAX 500
vector <int> pre[MAX];
int val[MAX];
struct node{
int next;
int wei;
};
vector <node> adj[MAX];
int n,m,c1,c2;
int vis[MAX];
int cost[MAX];
void init(){
for(int i=0;i<n;i++){
adj[i].clear();
pre[i].clear();
val[i]=0;
vis[i]=0;
cost[i]=-1;
}
path.clear();
}
void dij(int x){
//方便后面dfs
for(int i=0;i<n;i++){
pre[i].push_back(i);
}
int newp=x;
vis[newp]=1;
cost[newp]=0;
for(int i=0;i<n-1;i++){
for(int j=0;j<adj[newp].size();j++){
int u=adj[newp][j].next;
int c=adj[newp][j].wei;
if(vis[u]==0){
if(cost[u]>cost[newp]+c || cost[u]==-1){
pre[u].clear();
cost[u]=cost[newp]+c;
pre[u].push_back(newp);
}else if(cost[u]==cost[newp]+c){
pre[u].push_back(newp);
}
}
}
int min=123123123;
for(int j=0;j<n;j++){
if(cost[j]!=-1 && vis[j]==0){
if(cost[j]<min){
min=cost[j];
newp=j;
}
}
}
vis[newp]=1;
}
}
vector <int> path;
vector <int> tmppath;
void dfs(int v,int &ans,int &maxx){
if(v==c1){
ans++;
//也自己节点单独入栈
tmppath.push_back(v);
//当前路径的点权
int tmp=0;
for(int i=tmppath.size()-1;i>=0;i--){
int a=tmppath[i];
tmp+=val[a];
}
//判断是否最优
if(tmp>maxx){
maxx=tmp;
//vector直接赋值
path=tmppath;
}
//叶子节点单独出栈
tmppath.pop_back();
return;
}
//入栈
tmppath.push_back(v);
for(int i=0;i<pre[v].size();i++){
dfs(pre[v][i],ans,maxx);
}
//出栈
tmppath.pop_back();
}
传入终点
//int ans[MAX];
//int flag[MAX];
//int maxx=0;
//这种dfs用vis来标记是否访问过,不记录访问路径,会出错,
//因为多条路径时,存在边重合,而vis已经为1,无法再次访问
//int dfs(int x,int &num,int value){
// flag[x]=1;
// value+=val[x];
// for(int i=0;i<pre[x].size();i++){
// int u=pre[x][i];
// if(u==x){
// num++;
// if(maxx<value){
// maxx=value;
// }
// }else if(flag[u]==0){
// dfs(u,num,value);
// }
// }
// return maxx;
//}
int main(){
freopen("in.txt","r",stdin);
scanf("%d %d %d %d",&n,&m,&c1,&c2);
init();
for(int i=0;i<n;i++){
scanf("%d",&val[i]);
}
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
node tmp;
tmp.next=a;
tmp.wei=c;
adj[b].push_back(tmp);
tmp.next=b;
adj[a].push_back(tmp);
}
dij(c1);
int ans=0,maxx=0;
dfs(c2,ans,maxx);
printf("%d %d\n",ans,maxx);
return 0;
}