http://poj.org/problem?id=3592
每次做联通分量的题都是细节方面出错 伤不起呀
一张图 有些点是有矿可走 有些不可走 有些是时空转换点
矿车从左上开始走问最多能才多少矿
1,把二维图变成一维 由于时空转换点的存在使图存在了环
2,缩点 把环缩成一个点
3,重新建树,
4,搜索最多矿
以后再也不在Tarjan里进行重建图了 太容易出错了
果断在Tarjan后再dfs重新建图 虽然效率低了点但是不容易出错
而且只要整体算法选择正确 是不会超时的
由于数据小 所以dfs搜索最多矿就可以 不过要标记
代码及其注释:
#include<iostream> #include<cstring> #include<stack> #include<cstdio> #include<algorithm> #include<queue> using namespace std; const int N=2005; struct node { struct tt *next; int ores; }mem[N]; struct node1 { struct tt *next; }mem1[N]; struct tt { struct tt *next; int j; }; int transfer[N]; int deep; char path[50][50]; int low[N]; int dfn[N]; bool visited[N]; bool in[N]; stack<int>str; int uppoint[N]; int sum[N]; int ans; void build(int i,int j) { struct tt *t=new tt; t->j=j; t->next=mem[i].next; mem[i].next=t; } void Clearlist(int n)//清理邻接表 { struct tt *t; for(int i=0;i<n;++i) { while(mem[i].next!=NULL) { t=mem[i].next; mem[i].next=t->next; delete t; } while(mem1[i].next!=NULL) { t=mem1[i].next; mem1[i].next=t->next; delete t; } } } void rebuild(int i,int j) { struct tt *t=new tt; t->j=j; t->next=mem1[i].next; mem1[i].next=t; } void Tarjan(int x) {//cout<<x<<endl; ++deep; dfn[x]=low[x]=deep; visited[x]=true; in[x]=true; str.push(x); struct tt *t=mem[x].next; while(t!=NULL) { if(visited[t->j]==false) { Tarjan(t->j); low[x]=min(low[x],low[t->j]); }else if(in[t->j]==true) { low[x]=min(low[x],dfn[t->j]); } t=t->next; } if(low[x]==dfn[x]) { int num=0; while(str.top()!=x) { uppoint[str.top()]=x;//缩点 in[str.top()]=false; num+=mem[str.top()].ores;//把环内每个点的量加起来 str.pop(); } uppoint[str.top()]=x; in[str.top()]=false; num+=mem[str.top()].ores; str.pop(); sum[x]=num; } } int dist[N]; void dfsans(int x) { if(mem1[x].next==NULL)//搜到头就看是不是答案 { ans=max(ans,dist[x]); return ; } struct tt *t=mem1[x].next; while(t!=NULL) { if(dist[t->j]<dist[x]+sum[t->j])//只有可更新才往下搜 { dist[t->j]=dist[x]+sum[t->j]; dfsans(t->j); } t=t->next; } } void findans() { memset(dist,-1,sizeof(dist));//有量为0 的情况 初始化要为-1 dist[0]=sum[0]; dfsans(0); } void dfs(int x) { visited[x]=true; struct tt *t=mem[x].next; while(t!=NULL) { if(uppoint[x]!=uppoint[t->j])//属于不同的环则对两个环的缩点建边,即使t->j搜过了也得建边 rebuild(uppoint[x],uppoint[t->j]); if(visited[t->j]==false) { dfs(t->j); } t=t->next; } } void rebuild_map() { memset(visited,false,sizeof(visited)); dfs(0); } int main() { int T; int n,m; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); getchar(); for(int i=0;i<n;++i) { gets(path[i]); } int num=0; for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { int I=i*m+j;//刚开始把m写成n了 当时怎么想的?? if(path[i][j]=='#') {mem[I].ores=0;continue;} if(path[i][j]<='9'&&path[i][j]>='0') { mem[I].ores=path[i][j]-'0'; } else { transfer[num]=I;++num; mem[I].ores=0; } if(j+1<m&&path[i][j+1]!='#') build(I,i*m+j+1); if(i+1<n&&path[i+1][j]!='#') build(I,(i+1)*m+j); } } for(int i=0;i<num;++i) { int x,y; scanf("%d %d",&x,&y); if(path[x][y]!='#'&&(x*m+y)!=transfer[i]) build(transfer[i],x*m+y); } memset(visited,false,sizeof(visited)); memset(in,false,sizeof(in)); while(!str.empty()) str.pop(); memset(uppoint,-1,sizeof(uppoint)); memset(sum,0,sizeof(sum)); deep=0; Tarjan(0); rebuild_map();//重新建图 ans=0; findans();//找答案 printf("%d\n",ans); Clearlist(n*m); } return 0; }