您的位置:首页 > 其它

bzoj 1924: [Sdoi2010]所驼门王的宝藏 (tarjan缩点+spfa)

2016-09-19 15:43 441 查看

1924: [Sdoi2010]所驼门王的宝藏

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 854  Solved: 349

[Submit][Status][Discuss]

Description



Input

第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“自由门”。 保证 1≤xi≤R,1≤yi≤C,所有的传送门位置互不相同。

Output

只有一个正整数,表示你确定的路线所经过不同藏宝宫室的最大数目。

Sample Input

10 7 7

2 2 1

2 4 2

1 7 2

2 7 3

4 2 2

4 4 1

6 7 3

7 7 1

7 5 2

5 2 1

Sample Output

9

HINT

测试点编号 N R C 1 16 20 20 2 300 1,000 1,000 3 500 100,000 100,000 4 2,500 5,000 5,000 5 50,000 5,000 5,000 6 50,000 1,000,000 1,000,000 7 80,000 1,000,000 1,000,000 8 100,000 1,000,000 1,000,000 9 100,000
1,000,000 1,000,000 10 100,000 1,000,000 1,000,000

Source



[Submit][Status][Discuss]

题解:tarjan缩点+spfa

用tarjan缩点将图减小,然后用spfa跑最长路即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#define N 2000000
#define M 100003
#define pa pair<int,int>
using namespace std;
int m,n,x[M],y[M],opt[M],dis[M],can[M],val[M];
int point[N*2],next[N*2],v[N*2],ins[M],top,ans;
int head
,nxt
,c
,dfsn[M],low[M],belong[M],st
,cnt,sz,tot;
int posy[10]={-1,0,1,-1,1,-1,0,1},posx[10]={-1,-1,-1,0,0,1,1,1};
vector<int> line[M*10],row[M*10];
map<pa,int> mp;
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
//cout<<x<<" "<<y<<endl;
}
void build(int x,int y)
{
tot++; nxt[tot]=head[x]; head[x]=tot; c[tot]=y;
}
void tarjan(int x)
{
low[x]=dfsn[x]=++sz;
ins[x]=1; st[++top]=x;
for (int i=point[x];i;i=next[i])
if (!dfsn[v[i]])
{
tarjan(v[i]);
low[x]=min(low[x],low[v[i]]);
}
else if (ins[v[i]]) low[x]=min(low[x],dfsn[v[i]]);
if (low[x]==dfsn[x])
{
++cnt;
int j;
do
{
j=st[top--];
ins[j]=0;
belong[j]=cnt;
}while(j!=x);
}
}
void spfa()
{
queue<int> p;
memset(dis,0,sizeof(dis));
memset(can,0,sizeof(can));
for (int i=1;i<=cnt;i++)
if (!ins[i])
{
can[i]=1; dis[i]=val[i];
p.push(i);
}
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=head[now];i;i=nxt[i])
if (dis[c[i]]<dis[now]+val[c[i]])
{
dis[c[i]]=dis[now]+val[c[i]];
if (!can[c[i]])
{
can[c[i]]=1;
p.push(c[i]);
}
}
can[now]=0;
}
for (int i=1;i<=cnt;i++)
ans=max(ans,dis[i]);
}
int main()
{
int r,c;
scanf("%d%d%d",&n,&r,&c);
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&x[i],&y[i],&opt[i]);
line[x[i]].push_back(i);
row[y[i]].push_back(i);
mp[make_pair(x[i],y[i])]=i;
}
for (int i=1;i<=n;i++)
{
if (opt[i]==1){
int k=line[x[i]].size();
for (int j=0;j<k;j++)
if (line[x[i]][j]!=i) add(i,line[x[i]][j]);
}
else
if (opt[i]==2)
{
int k=row[y[i]].size();
for (int j=0;j<k;j++)
if (row[y[i]][j]!=i) add(i,row[y[i]][j]);
}
else
{
for (int j=0;j<8;j++)
{
int xx=posx[j]+x[i];
int yy=posy[j]+y[i];
if (xx>0&&yy>0&&xx<=r&&yy<=c)
if (mp[make_pair(xx,yy)])
add(i,mp[make_pair(xx,yy)]);
}
}
}
//cout<<tot<<endl;
for (int i=1;i<=n;i++)
if (!dfsn[i]) tarjan(i);
//cout<<cnt<<endl;
for (int i=1;i<=n;i++)
val[belong[i]]++;
tot=0;
memset(ins,0,sizeof(ins));
for (int i=1;i<=n;i++)
for (int j=point[i];j;j=next[j])
if (belong[i]!=belong[v[j]])
build(belong[i],belong[v[j]]),ins[belong[v[j]]]++;
//cout<<"!"<<endl;
spfa();
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: