2018.7.19 题解

日狗了没有自动保存

题目找不到留言,我私发

T1 城市轰炸

题目大意

给出一张有向图,可能有环,求最长链

思路

求最长链我们可以用拓扑排序。但是拓扑排序不能有环,怎么处理呢?其实环就是一个强联通分量,所以我们可以用tarjan把强联通分量求出来,并且将其合并成一个点。这样问题就解决了。

代码


#include<cstdio>
using namespace std;
const int N=1e6+1;
int tot,top,num,ans;
int first[N],next[N],en[N];
int first1[N],next1[N],en1[N];
int dfn[N],low[N],stack[N],MS[N],r[N];
int f[N],g[N],d[N],q[N],bel[N];
bool bz[N],vis[N];
inline int read()
{
    int X=0,w=1; char ch=0;
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
inline int max(int x,int y)
{
    return x>y?x:y;
}
inline int min(int x,int y)
{
    return x<y?x:y;
}
inline void insert(int x,int y)
{
    next[++tot]=first[x];
    first[x]=tot;
    en[tot]=y;
}
inline void insert1(int x,int y)
{
    next1[++tot]=first1[x];
    first1[x]=tot;
    en1[tot]=y;
    d[y]++;
}
inline void tarjan(int x)
{
    MS[MS[0]=1]=x;
    while(MS[0])
    {
        if(!dfn[x=MS[MS[0]]])
        {
            dfn[x]=low[x]=++tot;
            r[stack[++top]=x]=first[x];
            bz[x]=vis[x]=true;
        }
        bool enter=false;
        for(int i=r[x];i;i=next[i])
            if(!vis[en[i]])
            {
                r[x]=next[i];
                MS[++MS[0]]=en[i];
                enter=true;
                break;
            }else
                if(bz[en[i]]) low[x]=min(low[x],dfn[en[i]]);
        if(enter) continue;
        if(dfn[x]==low[x])
        {
            num++;
            do
            {
                bel[stack[top]]=num;
                bz[stack[top--]]=false;
            }while(stack[top+1]!=x);
        }
        low[MS[--MS[0]]]=min(low[MS[MS[0]]],low[x]);
    }
}
int main()
{
    freopen("bomb.in","r",stdin);
    freopen("bomb.out","w",stdout);
	int n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        insert(x,y);
    }
    tot=0;
    for(int i=1;i<=n;i++)
        if(!vis[i]) tarjan(i);
    tot=0;
    for(int i=1;i<=n;i++)
    {
        g[bel[i]]++;
        for(int j=first[i];j;j=next[j])
            if(bel[i]^bel[en[j]]) insert1(bel[i],bel[en[j]]);
    }
    int l=0,r=0;
    for(int i=1;i<=n;i++)
        if(!d[i]) f[q[++r]=i]=g[i];
    while(l<r)
    {
        int x=q[++l];
        if(!first1[x]) ans=max(ans,f[x]);
        for(int i=first1[x];i;i=next1[i])
        {
            f[en1[i]]=max(f[en1[i]],f[x]+g[en1[i]]);
            if(!--d[en1[i]]) q[++r]=en1[i];
        }
    }
    printf("%d\n",ans);
    return 0;
}

T2 密室

题目大意

有一坨房间,房间里可能有门或者钥匙。我们初始在房间x,要走到房间y。门通向另一个房间,但需要特定的数把钥匙才能开。求x到y的最短路径。

思路

看上去没思路,于是就写个bfs,发现bfs可以过。

代码


#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
struct node
{
	int dot,s,step;
	node(){}
	node(int x,int y,int z):dot(x),s(y),step(z){}
};
struct node1
{
	int to,s;
	node1(){}
	node1(int x,int y):to(x),s(y){}
};
int n,m,k,a[5005];
bool b[5005][2048];
queue<node> p;
vector<node1> c[5005];
void bfs()
{
	p.push(node(1,a[1],0));
	while (!p.empty())
	{
		node u=p.front();
		p.pop();
		if (u.dot==n)
		{
			cout<<u.step;
			return;
		}
		for (int i=0;i<c[u.dot].size();i++)
		{
			int v=c[u.dot][i].to;
			if ((u.s&c[u.dot][i].s)==c[u.dot][i].s&&b[c[u.dot][i].to][u.s|a[v]]==0) 
			{
				b[c[u.dot][i].to][u.s|a[v]]=1;
				p.push(node(v,u.s|a[v],u.step+1));
			}
		}
	}
}
int main()
{
	freopen("room.in","r",stdin);
	freopen("room.out","w",stdout);
	cin>>n>>m>>k;
	int x,y,z,t;
	for (int i=1;i<=n;i++) 
	{
		for (int j=1;j<=k;j++)
		{
			cin>>x;
			a[i]=a[i]*2+x;
		}
	}
	for (int i=1;i<=m;i++)
	{
		cin>>y>>z;
		t=0;
		for (int j=1;j<=k;j++)
		{
			cin>>x;
			t=t*2+x;
		}
		c[y].push_back(node1(z,t));
	}
	bfs();
}

T3 序列

思路

莫队算法,专门开一篇填坑

发表评论

电子邮件地址不会被公开。 必填项已用*标注