您的位置:首页 > 其它

poj3592 tarjan缩点+spfa

2014-08-12 12:54 323 查看
因为存在*,所以可以会构成强连通量,所以先将图缩点,然后新建图,从0,0开始spfa遍历找到最大值即可

刚开始做这种矩阵的连通量,一开始还不知道怎么找强联通,原来- -。只要按照题意把每条边连接起来即可- - 。

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int First[5000],Next[5000],to[5000],kk;
int First1[5000],Next1[5000],to1[5000],kk1;
int dfn[3000],low[3000],sta[3000],sum[3000],belong[3000],id,cnt,top;
int var[3000];
bool insta[3000];
char ch[50][50];
int n,m;
void addedge(int a,int b)
{
to[kk]=b;
Next[kk]=First[a];
First[a]=kk++;
}
void addedge1(int a,int b)
{
to1[kk1]=b;
Next1[kk1]=First1[a];
First1[a]=kk1++;
}
void tarjan(int v)
{
low[v]=dfn[v]=++id;
sta[++top]=v;
insta[v]=1;
for(int i=First[v];i!=-1;i=Next[i])
{
int j=to[i];
if(dfn[j]==-1)
{
tarjan(j);
low[v]=min(low[v],low[j]);
}
else if(insta[j])
low[v]=min(low[v],dfn[j]);
}
if(low[v]==dfn[v])
{
cnt++;
do
{
insta[sta[top]]=0;
belong[sta[top]]=cnt;
sum[cnt]+=var[sta[top]];
} while (sta[top--]!=v);
}
}
void solve()
{
id=cnt=top=0;
memset(dfn,-1,sizeof(dfn));
memset(insta,0,sizeof(insta));
memset(sum,0,sizeof(sum));
memset(belong,0,sizeof(belong));;
tarjan(0);     //由于从0,0开始,所以还要遍历0 ,0点即可
//for(int i=1;i<=cnt;i++)
//cout<<sum[i]<<endl;
kk1=1;
memset(First1,-1,sizeof(First1));
for(int i=0;i<n*m;i++)
for(int j=First[i];j!=-1;j=Next[j])
{
int h=to[j];
if(belong[i]!=belong[h])
addedge1(belong[i],belong[h]);  //新建spfa图
}
}
void spfa()
{
int dist[2000];
bool vis[2000];
memset(vis,0,sizeof(vis));
memset(dist,0,sizeof(dist));
queue<int>que;
int k=belong[0];
que.push(k);
dist[k]=sum[k];
while(!que.empty())
{
int v=que.front();
que.pop();
vis[v]=0;
for(int i=First1[v];i!=-1;i=Next1[i])
{

int j=to1[i];
if(dist[j]<dist[v]+sum[j])
{
dist[j]=dist[v]+sum[j];
if(!vis[j])
vis[j]=1,que.push(j);
}
}
}
int maxn=0;
for(int i=1;i<=cnt;i++)    //cnt-  -.一开始写成n,,,各种wa
maxn=max(maxn,dist[i]);
printf("%d\n",maxn);
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d %d",&n,&m);
kk=1;
memset(First,-1,sizeof(First));
for(int i=0;i<n;i++)
{
scanf("%s",ch[i]);
for(int j=0;j<m;j++)  //对图的处理,将每一条边连接起来
{
if(ch[i][j]=='#')
{
var[i*m+j]=0;
continue;
}
if(ch[i][j]=='*')
var[i*m+j]=0;
else
var[i*m+j]=ch[i][j]-'0';
if(i>0&&ch[i-1][j]!='#')
addedge((i-1)*m+j,i*m+j);
if(j>0&&ch[i][j-1]!='#')
addedge(i*m+j-1,i*m+j);
}
}
for(int i=0;i<n;i++)      //寻找瞬移的点
for(int j=0;j<m;j++)
if(ch[i][j]=='*')
{
int a,b;
scanf("%d %d",&a,&b);
if(ch[a][b]=='#')continue;
addedge(i*m+j,a*m+b);
}
solve();
spfa();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: