poj 3592 & uestc 1315

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

http://www.acm.uestc.edu.cn/problem.php?pid=1315

题目大意:给定一个矩阵,西南角为起点,每个单元都有一定价值的金矿(#表示岩石,不可达,*表示时空门,可以到达指定单元),队#外,每个点只能向右走或向下走,而且可以重复经过一个点。现在要求得最多可以获得多大利益 。

思路:原矩阵可以看成一个有向图,因为可以重复经过一个点,所以如果图中有环(因为有环),则环内的所有值都可以取完的,所以把环缩成一个点后,就成一棵有向无环图。从起点进行DFS记忆化搜索找最大值就好了。

PS:在进行找环缩点时,我认为从起点开始就行了,但却过不了,RE了,而对每一个点都进行检查缩点,则正确了。不解中~~~~

uestc 上的数据可能比较强。

View Code
                        #include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<bitset>
#include<string>
#include<climits>
#include<cstdio>
#include<vector>
#include<utility>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define IN puts("in")
#define OUT puts("out")
#define FR(x) freopen(x,"r",stdin)
#define FW(x) freopen(x,"w",stdout)
#define MSET(x,y) memset(x,y,sizeof(x))
#define ST system("pause")
using namespace std;
const int maxn = 100000;
const int N = 2500;
struct nd{
        int u,v,next;
}edge[maxn];
int head[N],vis[N],dfn[N],low[N],belong[N],st[N],val[N],c[N];
int ecnt,cnt,idx,tp,ans;
char str[50][59];

void add(int u,int v)
{
        if(u==v)return;
        edge[ecnt].u = u;
        edge[ecnt].v = v;
        edge[ecnt].next = head[u];
        head[u] = ecnt++;
}

void init()
{
        ecnt = cnt = idx = tp = 0;
        MSET(vis,0);
        MSET(dfn,0);
        MSET(c,0);
        MSET(head,-1);
        MSET(val,0);
}

void tarjan(int u)
{
        int i,v;
        dfn[u] = low[u] = ++idx;
        vis[u] = 1;
        st[++tp] = u;
        for(i = head[u]; i != -1; i = edge[i].next){
                v = edge[i].v;
                if(!dfn[v]){
                        tarjan(v);
                        low[u] = min(low[v],low[u]);
                }else if(vis[v])low[u] = min(dfn[v],low[u]);
        }
        if(dfn[u]==low[u])
        {
                cnt++;
                do{
                        v = st[tp--];
                        vis[v] = 0;
                        belong[v] = cnt;
                        c[cnt] += val[v];
                }while(v!=u);
        }
}

void dfs(int pre,int u,int sum)
{
        int i;
        if(val[u]>=sum)return ;
        val[u] = sum;
        ans=max(ans,sum);
        for(i = head[u]; i != -1; i = edge[i].next)if(edge[i].v!=pre)
                dfs(u,edge[i].v,sum+c[edge[i].v]);
}

void processing(int n,int m)
{
        int i,j,k,t,u,v;
        for(i = 0; i < n; ++ i)scanf("%s",str[i]);
        for(i = 0; i < n; ++ i)
                for(j = 0; j < m; ++ j)
                        if(str[i][j]!='#'){
                                if(i+1<n&&str[i+1][j]!='#')
                                        add(i*m+j+1,(i+1)*m+j+1);
                                if(j+1<m&&str[i][j+1]!='#')
                                        add(i*m+j+1,i*m+j+2);
                        }
        for(i = 0; i < n; ++ i)
                for(j = 0; j < m; ++ j)
                        if(str[i][j]=='*')
                        {
                                scanf("%d %d",&u,&v);
                                if(str[u][v]!='#')
                                add(i*m+j+1,u*m+v+1);
                        }
        for(i = 0; i < n; ++ i)
                for(j = 0; j < m; ++ j)
                        if(str[i][j]!='#'&&str[i][j]!='*')
                                val[i*m+j+1] = str[i][j] - '0';
        for(i = 1; i <= n*m; ++ i)if(!dfn[i])tarjan(i);
        k = ecnt; ecnt = 0;
        MSET(head,-1);
        for(i = 0; i < k; ++ i)
        {
                u = belong[edge[i].u];
                v = belong[edge[i].v];
                add(u,v);
        }
        ans = 0;
        MSET(val,-1);
        dfs(-1,belong[1],c[belong[1]]);
        printf("%d\n",ans);
}
int main()
{
        int t,n,m;
        scanf("%d",&t);
        while(t--)
        {
                scanf("%d %d",&n,&m);
                init();
                processing(n,m);
        }
        return 0;
}

 

 

posted on 2012-07-06 12:25  aigoruan  阅读(177)  评论(0)    收藏  举报

导航