感觉这道题很水,虽然过的人不多,觉得很恶心,思路还是懂得,但写的时候很麻烦,主要是代码的功底不好,,,,这题可以练代码量。自己写了你才懂得的,搞了半天,,,,
回正题:给出一个n*m的矩阵,每个格子可能放有0~9,#,*。0~9代表金矿的数量,#代表阻碍,不能够走,*代表传送点,可以瞬间传送到特定的位置,对于传送点的传送功能可以无限使用,也可以不用。初始时你开着一辆坦克在最左上角,你只能往右或者往下走,如果该格子上放有金矿的话你可以把他拿走,但只能拿一次。问最后你能够拿到最多的金矿的数量。
思路 :只能往右或者往下走,将这些节点构成一个有向图,但是因为有传送门的存在这个图中可能会有环,在一个强联通分支内,想到用tarjan进行缩点,环内所有的价值都能拿到,这时候有向图中没有环而变成了一个树,然后在这个树中找最长路径就可以了。
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int NN = 1605;
struct Edge
{
int v,w;
};
int n,m;
char map[50][50];
int dfn[NN],low[NN],index,scc,belong[NN],dis[NN];
int score[NN],w[NN];
int magic[NN],cnt;
int s[NN],top;
bool instack[NN],vis[NN];
vector<int> Grap[NN];
vector<Edge> GNew_[NN];
void init()
{
scanf("%d%d",&n,&m);
getchar();
cnt = 0;
for(int i=0;i<NN;i++)
{
Grap[i].clear();
GNew_[i].clear();
}
for(int i=0;i<n;i++)
scanf("%s",map[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
int k = i*m+j;
if(map[i][j]=='#')
score[k] = -1;
else
{
if(map[i][j]=='*')
{
magic[cnt++] = k;
score[k] = 0;
}
else
score[k] = map[i][j]-'0';
if(i+1<n && map[i+1][j]!='#')
Grap[k].push_back(k+m);
if(j+1<m && map[i][j+1]!='#')
Grap[k].push_back(k+1);
}
}
for(int i=0;i<cnt;i++)
{
int p,q,v;
scanf("%d%d",&p,&q);
v = p*m+q;
if(score[v]==-1) continue;
Grap[magic[i]].push_back(v);
}
}
void tarjan(int u)
{
int v;
dfn[u] = low[u] = ++index;
s[++top] = u;
instack[u] = true;
for(int i=0;i<Grap[u].size();i++)
{
v = Grap[u][i];
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[v],low[u]);
}
else if(instack[v])
low[u] = min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
w[++scc] = 0;
while(true)
{
v = s[top--];
instack[v] = false;
belong[v] = scc;
w[scc] += score[v];
if(v==u)
break;
}
}
}
void rebuilt()
{
top = scc = index = 0;
memset(instack,false,sizeof(instack));
memset(dfn,0,sizeof(dfn));
for(int i=0;i<n*m;i++)
if(!dfn[i])
tarjan(i);
for(int u=0;u<n*m;u++)
for(int i=0;i<Grap[u].size();i++)
{
int v = Grap[u][i];
if(belong[u]!=belong[v])
{
Edge e = {belong[v],w[belong[v]]};
GNew_[belong[u]].push_back(e);
}
}
Edge e = {belong[0],w[belong[0]]};
GNew_[0].push_back(e);
}
int spfa(int s)
{
memset(dis,-1,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[s] = 0;
vis[s] = true;
queue<int> q;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for(int i=0;i<GNew_[u].size();i++)
{
int v = GNew_[u][i].v;
int w = GNew_[u][i].w;
if(dis[v]<dis[u]+w)
{
dis[v] = dis[u]+w;
if(!vis[v])
{
q.push(v);
vis[v] = false;
}
}
}
}
int ans = 0;
for(int i=0;i<=scc;i++)
ans = max(ans,dis[i]);
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
rebuilt();
int answ = spfa(0);
printf("%d\n",answ);
}
return 0;
}
poj 3592(强连连通分量+缩点+重建图形+spfa求最长路)
最新推荐文章于 2019-08-08 10:24:31 发布