zoukankan      html  css  js  c++  java
  • Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP

    题意:
    给一个(n)(m)边的连通图 每个边有一个权值(d) 当且仅当当前走过的步数(ge d)时 才可以走这条边 问从节点(1)到节点(n)的最短路

    好神的一道题 直接写做法喽

    首先我们对边按(d_i)由小到大排序 设(f_i)表示加上(1sim i-1)的所有边走(d_i)次后各点间的联通情况 (G)表示只连(1sim i-1)的边的邻接矩阵 这些我们可以用一个(01)邻接矩阵来存储 则有

    (f_i=f_{i-1}*G^{d_i-d_{i-1}})

    这很明显是一个矩阵快速幂的过程

    之后只需要判断(1)(n)之间是否联通 不连通就连下一条边继续判断 否则在当前的范围内二分判断

    这样的复杂度还是不够优 我们发现矩阵相乘的过程可以压位后来做 于是将一个矩阵的状态压成(n)(bitset<n>) 这样就可过了

    我的代码没有压位 而是直接暴力相乘 不过做了点小优化居然就过了~

    #include<bits/stdc++.h>
    using namespace std;
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define pa pair<int,int>
    #define mod 1000000007
    #define ll long long
    #define mk make_pair
    #define pb push_back
    #define fi fisrt
    #define se second
    #define cl(x) memset(x,0,sizeof x)
    #ifdef Devil_Gary
    #define bug(x) cout<<(#x)<<" "<<(x)<<endl
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #else
    #define bug(x)
    #define debug(...)
    #endif
    const int INF = 0x7fffffff;
    const int N=155;
    /*
    char *TT,*mo,but[(1<<15)+2];
    #define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
    inline int read(){
        int x=0,rev=0,ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return rev?-x:x;
    }
    struct data{
    	int u,v,t;
    	bool operator < (const data&ch){
    		return t<ch.t;
    	}
    }e[N]; 
    int cnt,n,m,tmp[N],sz,bin[32]={1};
    struct matrix{
    	bool v[N][N];
    	matrix operator * (const matrix&b){
    		matrix c;cl(c.v);
    		for(int j=1;j<=n;j++)
    			for(int i=1;i<=n;i++){
    				if(!v[j][i]) continue;
    				for(int k=1;k<=n;k++)
    					c.v[j][k]|=v[j][i]&&b.v[i][k];
    			}
    		return c;
    	}
    }g[N],G,f[N][32];
    bool judge(int x){
    	int pos=upper_bound(tmp+1,tmp+sz+1,x)-tmp-1,ret=x-tmp[pos];
    //	debug("x=%d pos=%d
    ",x,pos);
    	matrix d=g[pos];
    //	bug(d.v[1][n]);
    	for(int k=0;k<=30;k++){
    		if(bin[k]&ret){
    			d=d*f[pos][k];
    		}
    	}
    	return d.v[1][n];
    }
    int main(){
    #ifdef Devil_Gary
    	freopen("in.txt","r",stdin);
    #endif
    	n=read(),m=read();
    	for(int i=1;i<=30;i++) bin[i]=bin[i-1]<<1;
    	for(int i=1;i<=n;i++) g[1].v[i][i]=1;
    	for(int i=1;i<=m;i++){
    		e[++cnt].u=read(),e[cnt].v=read(),e[i].t=read();
    //		if(!e[i].t) g[1].v[e[i].u][e[i].v]=1;
    		tmp[++sz]=e[i].t;
    	} 
    	e[++cnt].u=n,e[cnt].v=n,e[cnt].t=0,tmp[++sz]=0;
    	sort(tmp+1,tmp+sz+1); 
    	sz=unique(tmp+1,tmp+sz+1)-tmp-1;
    	sort(e+1,e+cnt+1);
    	for(int i=1,j=1;i<=sz;i++){
    		for(;e[j].t<=tmp[i]&&j<=cnt;j++){
    			G.v[e[j].u][e[j].v]=1;
    		}
    		f[i][0]=G;
    		for(int k=1;k<=30;k++) f[i][k]=f[i][k-1]*f[i][k-1];
    		if(i==sz) continue;
    		int ret=tmp[i+1]-tmp[i];
    		g[i+1]=g[i]; 
    		for(int k=0;k<=30;k++){
    			if(bin[k]&ret){
    				g[i+1]=g[i+1]*f[i][k]; 
    			}
    		} 
    	}
    	int l=0,r=1e9+155;
    	while(l<r){
    		int mid=l+r>>1;
    		if(judge(mid)) r=mid;
    		else l=mid+1; 
    	}
    /*	debug("l=%d rr=%d
    ",l,tmp[sz]+n+1);*/
    	if(l==1e9+155) return puts("Impossible"),0;
    	return !printf("%d
    ",l); 
    }
    

    下面这份是压位的做法 我直接粘来的

    #include <bits/stdc++.h>
    using namespace std;
    int n, m;
    const int N = 160;
    struct edge
    {
        int a, b, c;
    } E[N];
    struct mat
    {
        bitset <N> d[N];
    } O, I, P, Q;
    int comp(edge x, edge y)
    {
        return x.c < y.c;
    }
    mat operator * (mat a, mat b)
    {
        mat c;
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= n; ++ j)
                if (a.d[i][j])
                    c.d[i] |= b.d[j];
        return c;
    }
    mat operator ^ (mat a, int b)
    {
        mat c = I;
        for (; b; b >>= 1, a = a * a)
            if (b & 1) c = c * a;
        return c;
    }
    void print(mat a)
    {
        for (int i = 1; i <= n; ++ i)
        {
            for (int j = 1; j <= n; ++ j)
                cerr << a.d[i][j] << " ";
            cerr << endl;
        }
    }
    int res;
    int main()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; ++ i)
            I.d[i][i] = 1;
        for (int i = 1; i <= m; ++ i)
            cin >> E[i].a >> E[i].b >> E[i].c;
        sort(E + 1, E + m + 1, comp);
        E[m + 1].c = E[m].c + n + 5;
        P = I; Q.d[n][n] = 1;
        for (int i = 1; i <= m + 1; ++ i)
        {
        	cout<<i<<endl; 
            mat tmp = P * (Q ^ (E[i].c - E[i - 1].c));
            if (!tmp.d[1][n])
            {
                Q.d[E[i].a][E[i].b] = 1;
                P = tmp;
                continue;
            }
            res = E[i - 1].c;
            while (!P.d[1][n]) P = P * Q, res ++;
            cout << res << endl;
            return 0;
        }
        cout << "Impossible" << endl;
    }
    
  • 相关阅读:
    UVa1225 Digit Counting
    UVa1586 Molar mass
    UVa1585 Score
    Java中的Set
    CentOS6.5 格式化大磁盘
    Ganglia监控Hadoop与HBase集群
    Hadoop HA + HBase环境搭建(二)————HBase环境搭建
    Hadoop HA + HBase环境搭建(一)————zookeeper和hadoop环境搭建
    在树莓派上安装MongoDB
    编译运行hadoop程序
  • 原文地址:https://www.cnblogs.com/devil-gary/p/8960679.html
Copyright © 2011-2022 走看看