• Instantaneous Transference(强连通分量及其缩点)


    http://poj.org/problem?id=3592

    题意:给出一个n*m的矩阵,左上角代表起始点,每个格子都有一定价值的金矿,其中‘#’代表岩石不可达,‘*’代表时空门可以到达指定格子,求出可以获得的最大价值。

    思路:时空门的存在可能会使得图中出现环,所以先对强连通分量进行缩点,然后对于缩点后的连通分量建立有向无环图,spfa求到起始点的最长路。

      1 #include <stdio.h>
      2 #include <iostream>
      3 #include <string.h>
      4 #include <queue>
      5 #include <stack>
      6 using namespace std;
      7 const int N=2020;
      8 const int INF=-1<<28;
      9 struct node
     10 {
     11     int u,v,w;
     12     int next;
     13 } edge1[N*2],edge2[N*2];//edge1[]存的是原始图的边,edge2[]存的是缩点后的边
     14 int low[N],dfn[N],sccno[N];//sccno[i]表示点i所属于的连通分量的编号
     15 int dis[N],head1[N],head2[N],val[N];//val[]存储每个连通分量的价值
     16 int n,m,scc_cnt,cnt,dfs_clock;
     17 bool vis[N];
     18 stack<int>S;
     19 
     20 void init()
     21 {
     22     cnt = 0;
     23     scc_cnt = 0;
     24     dfs_clock = 0;
     25     memset(val,0,sizeof(val));
     26     memset(low,0,sizeof(low));
     27     memset(dfn,0,sizeof(dfn));
     28     memset(sccno,0,sizeof(sccno));
     29     memset(head1,-1,sizeof(head1));
     30     memset(head2,-1,sizeof(head2));
     31 
     32 }
     33 void add(int u,int v,int w,node *edge,int *head)
     34 {
     35     edge[cnt].u = u;
     36     edge[cnt].v = v;
     37     edge[cnt].w = w;
     38     edge[cnt].next = head[u];
     39     head[u] = cnt++;
     40 }
     41 void Tarjan(int u)//求强连通分量
     42 {
     43     low[u]=dfn[u]=++dfs_clock;
     44     S.push(u);
     45     for (int i = head1[u]; i!=-1; i=edge1[i].next)
     46     {
     47         int v = edge1[i].v;
     48         if (!dfn[v])
     49         {
     50             Tarjan(v);
     51             low[u]=min(low[u],low[v]);
     52         }
     53         else if (!sccno[v])
     54         {
     55             low[u]=min(low[u],dfn[v]);
     56         }
     57     }
     58     if (low[u]==dfn[u])
     59     {
     60         ++scc_cnt;
     61         while(1)
     62         {
     63             int v = S.top();
     64             S.pop();
     65             sccno[v] = scc_cnt;
     66             if (v==u)
     67                 break;
     68         }
     69     }
     70 }
     71 void spfa(int s)//求缩点后的最长路
     72 {
     73     for (int i = 0; i <= n*m; i++)
     74     {
     75         dis[i]=INF;
     76         vis[i]=false;
     77     }
     78     dis[s] = 0;
     79     queue<int>q;
     80     q.push(s);
     81     vis[s] = true;
     82     while(!q.empty())
     83     {
     84         int u = q.front();
     85         q.pop();
     86         vis[u]=false;
     87         for (int i = head2[u]; i!=-1; i=edge2[i].next)
     88         {
     89             int v = edge2[i].v;
     90             int w = edge2[i].w;
     91             if (dis[v] < dis[u]+w)
     92             {
     93                 dis[v] = dis[u]+w;
     94                 if (!vis[v])
     95                 {
     96                     q.push(v);
     97                     vis[v]=true;
     98                 }
     99             }
    100 
    101         }
    102     }
    103 }
    104 int main()
    105 {
    106     int t;
    107     char map[102][102];
    108     scanf("%d",&t);
    109     while(t--)
    110     {
    111         scanf("%d%d",&n,&m);
    112         init();
    113         for(int i = 0; i < n; i++)
    114         {
    115             scanf("%s",map[i]);
    116         }
    117         for (int i = 0; i < n; i++)
    118         {
    119             for (int j = 0; j < m; j++)
    120             {
    121                 if (map[i][j]!='#')
    122                 {
    123                     if(i) add((i-1)*m+j,i*m+j,0,edge1,head1);
    124                     if(j) add(i*m+j-1,i*m+j,0,edge1,head1);
    125                     if (map[i][j]=='*')
    126                     {
    127                         int x,y;
    128                         scanf("%d%d",&x,&y);
    129                         if(map[x][y]!='#')
    130                             add(i*m+j,x*m+y,0,edge1,head1);
    131                     }
    132                 }
    133             }
    134         }
    135         for (int i = 0; i < n; i++)
    136         {
    137             if (!dfn[i])
    138                 Tarjan(i);
    139         }
    140         for (int i = 0; i < n; i++)
    141         {
    142             for (int j = 0; j < m; j++)
    143             {
    144                 if(map[i][j]!='*'&&map[i][j]!='#')
    145                 {
    146                     int num = sccno[i*m+j];
    147                     val[num]+=map[i][j]-'0';//记录每个连通分量的价值
    148                 }
    149             }
    150         }
    151         for (int u = 0; u < n*m; u++)
    152         {
    153             for (int j = head1[u]; j!=-1; j=edge1[j].next)
    154             {
    155                 int v = edge1[j].v;
    156                 if(sccno[u]!=sccno[v])
    157                 {
    158                     add(sccno[u],sccno[v],val[sccno[v]],edge2,head2);
    159                 }//对缩点后的连通分量建立有向图
    160             }
    161         }
    162         spfa(sccno[0]);//求出每个点到起始点的价值
    163         int max=-1;
    164         for (int i = 1; i <= scc_cnt; i++)
    165         {
    166             if (max < dis[i])
    167                 max = dis[i];//求出到原点的最大价值
    168         }
    169         int ans = max+val[sccno[0]];//总最大价值=到原点的最大价值+原点的价值
    170         printf("%d
    ",ans);
    171     }
    172     return 0;
    173 }
    View Code
  • 相关阅读:
    python操作MySQL数据库(转)
    python3.3.2中的关键字(转)
    HashMap的键值需要注意什么?
    为什么基本类型不能做为HashMap的键值?
    怎么确保一个集合不能被修改?
    Iterator和 ListIterator有什么区别?
    Iterator怎么使用?有什么特点?
    迭代器Iterator是什么?
    哪些集合类是线程安全的?
    Queue的element()和peek()方法有什么区别?
  • 原文地址:https://www.cnblogs.com/lahblogs/p/3551514.html
Copyright © 2020-2023  润新知