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
- 1003. Emergency (25)
- 1003. Emergency (25)-PAT
- (PAT)1003. Emergency (25)
- 1003. Emergency (25)
- 【C++】1003. Emergency (25)*
- 1003. Emergency (25)
- PAT 1003. Emergency (25)
- 1003. Emergency (25)
- 1003. Emergency (25)
- PAT 1003. Emergency (25)
- 1003. Emergency (25)
- 1003. Emergency (25)
- [PAT]1003. Emergency (25)
- 1003. Emergency (25)
- 1003. Emergency (25)
- 1003. Emergency (25)
- 1003. Emergency (25)
- 1003. Emergency (25)
- 【jQWidgets】导出数据
- Android 网络类型判断
- 昨天帐号被盗,密码被人改了
- 浮点数强制转换为整数高效替代方法
- Android-4.1.2触摸屏移植摸索过程-getevent 调试
- 1003. Emergency (25)
- UITextView如何关闭键盘
- linux等待队列wait_queue_head_t和wait_queue_t
- STM32F103学习笔记 (十一) USMART调试组件
- NDK编译C++库,
- Linux(centos6.5)安装jdk
- SqlServer2008删除日志
- Android getevent/senevent
- apache重定向去掉自动加上的querystring