poj 3592 & uestc 1315
http://poj.org/problem?id=3592
http://www.acm.uestc.edu.cn/problem.php?pid=1315
题目大意:给定一个矩阵,西南角为起点,每个单元都有一定价值的金矿(#表示岩石,不可达,*表示时空门,可以到达指定单元),队#外,每个点只能向右走或向下走,而且可以重复经过一个点。现在要求得最多可以获得多大利益 。
思路:原矩阵可以看成一个有向图,因为可以重复经过一个点,所以如果图中有环(因为有环),则环内的所有值都可以取完的,所以把环缩成一个点后,就成一棵有向无环图。从起点进行DFS记忆化搜索找最大值就好了。
PS:在进行找环缩点时,我认为从起点开始就行了,但却过不了,RE了,而对每一个点都进行检查缩点,则正确了。不解中~~~~
uestc 上的数据可能比较强。

#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; }