您的位置:首页 > Web前端

POJ 3592 Instantaneous Transference 强连通缩点+dp最长路

2017-08-18 20:28 369 查看

题目链接:

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

题意

在一个n*m的方格中,方格可以填三种类型的字符,

1.数字

2.’*’

3.’#’

数字代表他到达这儿所能获得的价值,*表示这点为传输机,走到这儿可以选择传送与它绑定的某个点,#代表墙壁,不能走到这儿。一个人从左上角走到右下角,在每个点只能往下或往右,在传输机位置处,可以选择传送或不传送,每个点的价值只能获得一次,问这个人能获得的最大价值。

思路

按照题中描叙的方式建图,缩点后形成dag。然后求dag上的最长路。

容易错的地方:起点(左上角)所在的连通分量的dp值为最终答案。这道题真的要细心,太容易出错了。

#include<cstdio>
#include<queue>
#include<iostream>
#include<vector>
#include<map>
#include<cstring>
#include<string>
#include<set>
#include<stack&g
fb44
t;
#include<algorithm>
#define cle(a) memset(a,0,sizeof(a))
#define inf(a) memset(a,0x3f,sizeof(a))
#define ll long long
#define Rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn =  1700;
vector<int> g[maxn],dag[maxn];
char mp[50][50];
int time,num;
int dfn[maxn],low[maxn],instack[maxn],scc[maxn],w[maxn],w2[maxn];
int dp[maxn];
stack<int> s;
void tarjan(int u)
{
dfn[u]=low[u]=++time;
instack[u]=1;
s.push(u);
for(int i=0,L=g[u].size();i<L;i++)
{
int v=g[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
num++;
int x;
do
{
x=s.top();s.pop();
w2[num]+=w[x];
instack[x]=0;
scc[x]=num;
}while(x!=u);
}
}
int find(int u)
{
if(dp[u]!=-INF)return dp[u];
dp[u]=w2[u];
for(int i=0;i<dag[u].size();i++)
{
int v=dag[u][i];
dp[u]=max(dp[u],w2[u]+find(v));
}
return dp[u];
}
int main()
{
int t;
//  freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
int n,m;
time=num=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(w,0,sizeof(w));
memset(w2,0,sizeof(w2));
memset(scc,-1,sizeof(scc));
while(!s.empty())s.pop();
scanf("%d%d",&n,&m);
for(int i=0;i<=(n*m);i++)
{
g[i].clear();
dag[i].clear();
}
for(int i=0;i<n;i++)
scanf("%s",mp[i]);
int cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
int t=i*m+j;
if(mp[i][j]>='0'&&mp[i][j]<='9')
w[t]=mp[i][j]-'0';
else if(mp[i][j]=='#')
dfn[t]=1;

if(i>0&&mp[i-1][j]!='#'&&mp[i][j]!='#')
{
int l=m*(i-1)+j;
g[l].push_back(t);
}
if(j>0&&mp[i][j-1]!='#'&&mp[i][j]!='#')
{
int l=m*i+j-1;
g[l].push_back(t);
}
if(mp[i][j]=='*')
{
int x,y;
scanf("%d%d",&x,&y);
int c=x*m+y;
if(mp[x][y]!='#')
g[t].push_back(c);
}
}

for(int i=0;i<(n*m);i++)
if(!dfn[i])tarjan(i);

for(int i=0;i<n*m;i++)
{
for(int j=0,L=g[i].size();j<L;j++)
if(scc[i]!=scc[g[i][j]])
{
dag[scc[i]].push_back(scc[g[i][j]]);
}
}

int ans=-INF;

for(int i=0;i<=num;i++)dp[i]=-INF;

for(int i=1;i<=num;i++)
find(i);
ans=dp[scc[0]];
printf("%d\n",ans);
}
}


另外还写了个数据生成的程序,对拍时发现网上一些ac代码竟然有些数据过不了

#include<cstdio>
#include<queue>
#include<iostream>
#include<vector>
#include<map>
#include<time.h>
#include<stdlib.h>
#include<cstring>
#include<string>
#include<set>
#include<stack>
#include<algorithm>
#define cle(a) memset(a,0,sizeof(a))
#define inf(a) memset(a,0x3f,sizeof(a))
#define ll long long
#define Rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
const int INF = ( 2e9 ) + 2;
int main()
{
srand(time(NULL));
freopen("in.txt","w",stdout);
int t=rand()%20;
printf("%d\n",t);
while(t--)
{
int n,m;
n=rand()%10+1;
m=rand()%10+1;
printf("%d %d\n",n,m);
int cnt=0;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
int f=rand()%7;
int t=rand()%10;
if(f==0)
{
printf("%c",'*');
cnt++;
}
else if(f==1)
printf("%c",'#');
else
printf("%c",t+'0');
}
printf("\n");
}
for(int i=0; i<cnt; i++)
{
int x,y;
x=rand()%n;
y=rand()%m;
printf("%d %d\n",x,y);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: