1003. Emergency (25)

来源:互联网 发布:冲之鸟礁放海星知乎 编辑:程序博客网 时间:2024/06/11 02:41

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 500vector <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){//方便后面dfsfor(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;}




0 0