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

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[N],nxt[N],c[N],dfsn[M],low[M],belong[M],st[N],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);  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值