zoukankan      html  css  js  c++  java
  • POJ3592 Instantaneous Transference题解

    题意:

      给一个矩形,矩形中某些点有一定数量的矿石,有些点为传送点,有些点为障碍。你驾驶采矿车(ore-miner truck,我也不知道是什么),从左上角出发,采尽量多的矿石,矿石不可再生。不能往左边或者上面走。传送点可以往左边或上面传。2<=n,m<=40

    分析:

      可以把矩形看作一张图,每个格子为一个点,每个格子与它右边和下面的点连接一条有向边。每个传送点与它传送的位置连接一条有向边。如果右边或下面为#那么不连。值得注意的是题目并没有保证传送点传送到的一定不是#,所以需要进行判断。

       这样,我们得到了一个点数|V|=n*m,边数最大|E|=O(n*m)的有向有环图。答案就是限制只能取一次的最长路。

      我们现在的任务就是把只能取一次抽象成另一种能实现的东西,不然暴力是指数级的。

      很显然,向后传送不需要考虑,只考虑传回前面,在图上的表现为成环,或者说同属一个强连通分量。

      很自然地就可以发现同属一个强连通分量的点都可以同时取到,我们考虑用tarjan缩点,这样建的就是一个DAG,在这个DAG上跑最长路,就是答案。

       这里值得一提的是,这里不能用dijkstra,同时我们可以下结论:求最长路时,dijkstra算法只适用于负权图,求最短路时,dijkstra算法只适用于正权图。所以这里要写SPFA。

    代码:用emacs写的,所以不要吐槽两格缩进

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<vector>
      5 #include<cstring>
      6 #include<stack>
      7 #include<queue>
      8 #include<algorithm>
      9 using namespace std;
     10 int low[1650],dfn[1650],arr[1650],scc[1650],al,cl,w[1650];
     11 vector<int> g[1650];
     12 vector<int> ng[1650];
     13 stack <int> sta;
     14 void tarjan(int now){
     15   low[now]=dfn[now]=++cl;
     16   sta.push(now);
     17   for(int i=0;i<g[now].size();i++){
     18     int k=g[now][i];
     19     if(arr[k])continue;
     20     if(!dfn[k]){
     21       tarjan(k);
     22       low[now]=min(low[now],low[k]);
     23     }else
     24       low[now]=min(low[now],dfn[k]);
     25   }
     26   if(low[now]==dfn[now]){
     27     al++;
     28     while(1){
     29       int u=sta.top();
     30       sta.pop();
     31       arr[u]=1;
     32       scc[u]=al;
     33       if(u==now) break;
     34     }
     35   }
     36 }
     37 int a[50][50];
     38 void readint(int n,int m){
     39   memset(arr,0,sizeof(arr));
     40   memset(w,0,sizeof(w));
     41   memset(dfn,0,sizeof(dfn));
     42   memset(low,0,sizeof(low));
     43   memset(scc,0,sizeof(scc));
     44   al=cl=0;
     45   for(int i=1;i<=n*m;i++)g[i].clear(),ng[i].clear();
     46   for(int i=1;i<=n;i++)
     47     for(int j=1;j<=m;j++){
     48       char x;cin>>x;
     49       if(x=='*')a[i][j]=10;
     50       else
     51     if(x=='#')a[i][j]=-1;
     52         else a[i][j]=(int)(x-48);
     53     }
     54   for(int i=1;i<=n;i++){
     55     for(int j=1;j<=m;j++){
     56       if(j+1<=m&&a[i][j+1]!=-1)g[i*m-m+j].push_back(i*m-m+j+1);
     57       if(i+1<=n&&a[i+1][j]!=-1)g[i*m-m+j].push_back(i*m+j);
     58       if(a[i][j]==10){
     59     int x,y;cin>>x>>y;
     60     if(a[x+1][y+1]==-1)continue;
     61     else g[i*m-m+j].push_back(x*m+y+1);
     62       }
     63     }
     64   }
     65 }
     66 void dij(int n){//SPFA找最长路
     67   queue <int> que;
     68   int dist[2000];
     69   memset(dist,0,sizeof(dist));
     70   dist[scc[1]]=w[scc[1]];
     71   que.push(scc[1]);
     72   while(!que.empty()){
     73     int k=que.front();
     74     for(int i=0;i<ng[k].size();i++){
     75       if(dist[k]+w[ng[k][i]]>dist[ng[k][i]]){
     76     dist[ng[k][i]]=dist[k]+w[ng[k][i]];
     77     que.push(ng[k][i]);
     78       }
     79     }
     80     que.pop();
     81   }
     82   int maxx=0;
     83   for(int i=1;i<=n;i++)maxx=max(maxx,dist[i]);
     84   cout<<maxx<<endl;
     85 }
     86 
     87 int main(){
     88   int t;cin >> t;
     89     while(t--){
     90     int n,m;
     91     cin>>n>>m;
     92     readint(n,m);
     93     for(int i=1;i<=n*m;i++)
     94       if(!arr[i])
     95     tarjan(i);//求强连通分量
     96     for(int i=1;i<=n*m;i++){
     97       for(int j=0;j<g[i].size();j++){
     98     if(scc[i]==scc[g[i][j]])continue;
     99     ng[scc[i]].push_back(scc[g[i][j]]);
    100       }
    101     }//缩点
    102     for(int i=1;i<=n;i++){
    103       for(int j=1;j<=m;j++){
    104     if(a[i][j]==-1||a[i][j]==10)continue;
    105     w[scc[i*m-m+j]]+=a[i][j];
    106       }
    107     }//算新的点权
    108     dij(al);//求最长路
    109   }
    110   return 0;
    111 }

      

     

  • 相关阅读:
    EF
    采用什么架构,才能够承受大访问量
    13个MVC的扩展
    c#与.NET的区别
    整合Spring.net到asp.net网站开发中初探
    C#多线程编程简述
    ASP.NET页面传值的几种方式
    正则RegEXp
    C#中Cache用法
    c#程序将excel文件转换成xml文件
  • 原文地址:https://www.cnblogs.com/1-1-1-1/p/6351565.html
Copyright © 2011-2022 走看看