【Gym-10167】Is-A,Has-A, Who Knowz-A【图的连通性】

题意:

        图中有两种连通关系,一种是is关系,一种是has关系。然后询问你m个问题,每个问题是x y z,表示x和z的关系是y,问你这种描述是否正确。

解法:

        在本题中需要搞清楚题意,题意不是很好懂。

        基本上题意就是,如果A和B是is关系,那么从A到B的路径上都是is边。

        如果A和B是has关系,那么A到B的路径上至少有一条has边。

        因此对于题目中给出的描述,如果A和B的关系是is关系,那么从A到B连一条is的边,如果关系是has,则从A到B连一条has边。

        由于is关系和has关系的判定方法不一样,因此我们建两个图,一个图中只放is边,一个图中has和is边都放,然后对于不同关系进行不同的判定。

        对于is关系,我们要求只有is边的图中两点连通。

        对于has关系,我们要求在有所有边的图中两点连通,并且这两点之间的路径上必须有一条has边。

        题目解析完了之后,剩下的就是如何求解了。求is关系不难,重点在于求has关系,如何判定两点之间的路径一定有一条has边呢。

        两种思路。

第一种思路:最短路

        给has边赋值为-1,给is边赋值为0,用Floyd求最短路。如果他们之间的距离小于0,那么说明这两点之间一定有has边。【这里需要注意,在更新最短路的时候可能会爆long long】

第二种思路:bfs【更可取】

        给每一个点都有一个vis值,vis == 0,表示该点不可达,vis == 1,表示该点可只用 is 边到达,vis == 2,表示到该点的路径上一定有一条has边。

        由此就可以使用在线算法,直接跑bfs求出结果。

总结:

        这里需要总结一下,对于这种求两点是否连通的问题,已经不是第一次遇到了。每一次遇到之后第一个想到的解法都是最短路,但是最后最短路要么不可行,要么不优。

        因此对于此类连通问题,以后需要第一时间想到bfs,然后加上适当的剪枝以及一些标记,实现目标。

代码【最短路】:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#define rep(i,a,b) for(ll i = a;i <= b;i++)
using namespace std;
const int N = 1000;
typedef long long ll;
const ll inf = 0x3f3f3f3f;

ll d1[N][N],d2[N][N];
ll n,m;
map<string,int> mp;
string s1,s2,s3;
string base1 = "is-a";
string base2 = "has-a";

ll get(string x)
{
	if(mp[x] != 0) return mp[x];
	mp[x] = ++n;
	return mp[x];
}

void Floyd()
{
	rep(k,1,n)
		rep(i,1,n)
			rep(j,1,n)
				if(d1[i][j] > d1[i][k]+d1[k][j]){
					d1[i][j] = (ll)d1[i][k]+(ll)d1[k][j];
					if(d1[i][j] < 0) d1[i][j] = -1;
				}
	rep(k,1,n)
		rep(i,1,n)
			rep(j,1,n)
				if(d2[i][j] > d2[i][k]+d2[k][j]){
					d2[i][j] = (ll)d2[i][k]+(ll)d2[k][j];
				}
}

int main()
{
	ios::sync_with_stdio(0);
    cin.tie(0);
    ll T;
    while(cin>>T>>m)
    {
    	n = 0;
    	mp.clear();
    	rep(i,0,N-1)
    		rep(j,0,N-1){
    			d1[i][j] = inf;
    			d2[i][j] = inf;
    		} 
     	rep(i,0,N-1) d1[i][i] = d2[i][i] = (ll)0;
    	rep(i,1,T)
        {
            cin>>s1>>s2>>s3;
            int x = get(s1), y = get(s3);
            if(s2 == base1) //is
            {
            	d1[x][y] = min(d1[x][y],(ll)0);
            	d2[x][y] = min(d2[x][y],(ll)0); //只有is
            }
            else{
            	d1[x][y] = (ll)-1;
            }
        }
        Floyd();
        rep(i,1,m)
        {
        	cin>>s1>>s2>>s3;
        	int xp = get(s1);
        	int yp = get(s3);
        	if(s2 == base1) //is
            {
                if(d2[xp][yp] == 0) cout<<"Query "<<i<<": true"<<endl;
                else cout<<"Query "<<i<<": false"<<endl;
            }
            else{
                if(d1[xp][yp] >= 0) cout<<"Query "<<i<<": false"<<endl;
                else cout<<"Query "<<i<<": true"<<endl;
            }
        }
    }
	return 0;
}

代码:【bfs】

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 1000;
const int M = 5*1e4+1000;

struct Edge{
	int to,next,w;
}e1[M],e2[M];
int head1[N],head2[N],tot1,tot2,n,m,vis[N];
map<string,int> mp;
string s1,s2,s3;
string base1 = "is-a";
string base2 = "has-a";
queue<int> q;

void init()
{
	n = 0;
	tot1 = tot2 = 1;
	rep(i,0,505) head1[i] = head2[i] = 0;
}

void add1(int x,int y,int w)
{
	e1[++tot1].to = y, e1[tot1].next = head1[x], head1[x] = tot1, e1[tot1].w = w;
}

void add2(int x,int y,int w)
{
	e2[++tot2].to = y, e2[tot2].next = head2[x], head2[x] = tot2, e2[tot2].w = w;
}

int get(string x)
{
	if(mp[x] != 0) return mp[x];
	mp[x] = ++n;
	return mp[x];
}

void bfs1(int s)
{
	rep(i,0,n) vis[i] = 0;
	//vis = 1:只有is,vis = 2:有has
	while(q.size()) q.pop();
	q.push(s);
	vis[s] = 1;
	while(q.size())
	{
		int x = q.front();
		q.pop();
		for(int i = head1[x]; i ; i = e1[i].next)
		{
			int y = e1[i].to;
			int z = e1[i].w;
			if(vis[y] == 2) continue;
			else if(vis[y] == 1 && (z == 2 || vis[x] == 2))
			{
				vis[y] = 2;
				q.push(y);
			}
			else if(vis[y] == 0)
			{
				if(z == 2 || vis[x] == 2){
					vis[y] = 2;
					q.push(y);
				}
				else{
					vis[y] = 1;
					q.push(y);
				}
			}
		}
	}
}

void bfs2(int s)
{
	rep(i,0,n) vis[i] = 0;
	while(q.size()) q.pop();
	q.push(s);
	vis[s] = 1;
	while(q.size())
	{
		int x = q.front();
		q.pop();
		for(int i = head2[x]; i ; i = e2[i].next)
		{
			int y = e2[i].to;
			if(vis[y]) continue;
			vis[y] = 1;
			q.push(y);
		}
	}
}

int main()
{
	ios::sync_with_stdio(0);
    cin.tie(0);
	int T;
	while(cin>>T>>m)
	{
		init();
		mp.clear();
		rep(i,1,T)
		{
			cin>>s1>>s2>>s3;
			int x = get(s1), y = get(s3);
			if(s2 == base1)  //add1:has+is   add2:is
			{
				add1(x,y,1);
				add2(x,y,1);
			}
			else add1(x,y,2);
		}
		rep(i,1,m)
		{
			cin>>s1>>s2>>s3;
			int xp = get(s1);
			int yp = get(s3);
			if(s2 == base1) //is
			{
				bfs2(xp);
				if(vis[yp] == 1) cout<<"Query "<<i<<": true"<<endl;
				else cout<<"Query "<<i<<": false"<<endl;
			}
			else{ //is+has
				bfs1(xp);
				if(vis[yp] == 2) cout<<"Query "<<i<<": true"<<endl;
				else cout<<"Query "<<i<<": false"<<endl;
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/82251159