【Gym - 100342J】 【Gym - 100345H】 【bitset在图论中的应用 传递闭包 or 三元环个数】

Andrew Stankevich Contest 28
Petrozavodsk, January – February 2008
Problem J. Triatrip
Input file: triatrip.in
Output file: triatrip.out
Time limit: 3 seconds
Memory limit: 256 megabytes
The travel agency “Four Russians” is offering the new service for their clients. Unlike other agencies that
only suggest one-way or roundtrip for airline tickets to their customers, “Four Russians” offers the brand
new idea — triatrip. Triatrip traveler starts in some city A, flies to some city B, then flies to some city
C, and returns to the city A.
Now the managers of the agency started to wonder, how many different triatrips they can offer to their
customers. Given a map of all possible flights, help them to find that out.
Input
The first line of the input file contains two integer numbers n — the number of cities that are served by
airlines that agree to sell their tickets via the agency (3 ≤ n ≤ 1500). The following n lines contain a
sequence of n characters each — the j-th character of the i-th line is ‘+’ if it is possible to fly from the
i-th city to the j-th one, and ‘-’ if it is not. The i-th character of the i-th line is ‘-’.
Output
Output one integer number — the number of triatrips that the agency can offer to its customers.
Example
triatrip.in triatrip.out
4
–+-
+–+
-+–
–+-

题意: 给一个邻接矩阵,问其中有多少条路径 是 A - B - C - A ?
分析:如果仅仅是用 邻接矩阵来存储 ,时间很容易不够,但是如果用bitset来存储就会减少很多时间。

假设有路径 A - B - C - A ,我们枚举 B-C ,然后找到C所有能够射入的点,找到所有射向B的点,然后两者& 一下,判一下其中有一个1,就知道有几个符合的。
这样算下来,其实多算了三倍,因为我们枚举的是B-C,同一条路径中,A-B,C- A,B-C这三条都是相同性质的。

#include<bits/stdc++.h>
using namespace std;
#define LL __int64

const int N = 1500+11;
bitset<N>bs_in[N],bs_out[N];  
void init(int n){
    for(int i=1;i<=n;i++) {
          bs_in[i].reset();
          bs_out[i].reset();
    }
}
int main(){
    freopen("triatrip.in","r",stdin);//必须加上,不然得WA
    freopen("triatrip.out","w",stdout);
    int n; cin>>n;
    init(n);
    for(int i=1;i<=n;i++){
        string s;cin>>s;
        for(int j=0;s[j];j++){
            if(s[j]=='+'&&i!=j+1) {
                bs_out[i][j+1]=1;
                bs_in[j+1][i]=1;
            }
        }
    }
    LL ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) continue;
            if(bs_in[j][i]) {
                ans+=(bs_out[j]&bs_in[i]).count();
            }
        }
    }
    cout<<ans/3<<endl;
return 0;
}

/*

4
--+-
+--+
-+--
--+-

*/

Problem H. Settling the Universe Up

Input file: settling.in
Output file: settling.out
Time limit: 2 seconds
Memory limit: 256 megabytes
The colonists from Earth are settling the Universe up. More and more young families choose to leave
the Earth for good in order to bring the human race to the new heights. Well, actually they just have
no way back because hypertunnels that are used for the colonization are one-way.
You work in the coordination center of the colonization. There are n planets that are used in the
process of colonization, numbered from 1 to n. Earth has number 1. Brave pathfinders sometimes put
a hypertunnel from one planet to another. The planets are numbered in order of decreasing of their
torsion power, so a hypertunnel can only exist from a planet with smaller number to a planet with
greater number. Sometimes, due to torsion fields distortion, hypertunnels disappear. Your task is to
trace all such events, quickly answer questions whether there exists a path from one planet to another,
and provide some other statistics.
After some period of working with pen and paper you decide to write a program to do the work for you.
Input
The first line of the input file contains n — the number of planets (1 ≤ n ≤ 200), and m — the number
of hypertunnels that exist at the moment you start writing the program. The following m lines describe
hypertunnels, each hypertunnel is described by two integer numbers: u and v — the planet where the
tunnel starts and the planet where the tunnel goes (1 ≤ u < v ≤ n).
The next line contains k — the number of events and queries (1 ≤ k ≤ 100 000, the number of events
doesn’t exceed 1000). The following k lines contain information about events and queries. Each event
is either “+ i j” if the hypertunnel between i and j is added, or “- i j” if the hypertunnel between i
and j has disappeared. No tunnel is created if there is a tunnel already, a tunnel can disappear only if
it exists. Each query is “? i j” and asks whether there is a path from planet i to planet j. In all events
and queries i < j.
Output
Output k+1 lines. The first line must contain the number of pairs of planets (u, v) such that it is possible
to get from planet u to planet v by hypertunnels that initially exist. After each event output the updated
number of pairs. After each query output “YES” or “NO”.

Example
settling.in settling.out
4 4
1 2
2 4
1 3
3 4
6
? 2 3
+ 2 3
- 1 3
- 1 2
+ 1 4
? 2 3

5
NO
6
6
3
4
YES

代码 :

#include<bits/stdc++.h>
using namespace std;
#define LL __int64

const int maxn = 1e3+11;
bitset<maxn> bs_out[maxn],bs[maxn];
int GetVal(int n){
    int ans=0;
    for(int i=1;i<=n;i++) bs[i].reset();
    for(int i=n;i>=1;i--){
        bs[i].set(i);
        for(int j=1;j<i;j++){
            if(bs_out[j][i])
                bs[j]|=bs[i];
        }
        ans+=bs[i].count();
    }
    return ans-n;
}
int main(){
     freopen("settling.in", "r", stdin);
     freopen("settling.out", "w", stdout);
    int n,m; scanf("%d%d",&n,&m);
    while(m--){
        int a,b;scanf("%d%d",&a,&b);
        bs_out[a][b]=1;
    }
    printf("%d\n",GetVal(n));
    int k; scanf("%d",&k);
    while(k--){
        char op[5];int u,v; scanf("%s%d%d",op,&u,&v);
        if(op[0]=='?') {
            if(bs[u][v]) puts("YES");
            else puts("NO");
        }else {
            if(op[0]=='+') bs_out[u][v]=1;
            else if(op[0]=='-') bs_out[u][v]=0;
            printf("%d\n",GetVal(n));
        }
    }
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值