CCPC FINAL 2017(Inkopolis-基环外向树)

直接对每种颜色建图,维护连通块个数。显然只要保证第i个点在第j个颜色下的度数。
原图是基环外向树,需要额外考虑那条边上的颜色是否全都一样。

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
                        For(j,m-1) cout<<a[i][j]<<' ';\
                        cout<<a[i][m]<<endl; \
                        } 
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 

typedef long double db;
#define EPS 1e-8
#define INF 1e100
#define M (4000+5)
#define N (4000+5)

namespace LP{
    db a[M][N];
    int idA[N],idB[M];
    int m,n;

    void put_out(int x){
        if(x == 0) printf("Infeasible\n");
        else printf("Unbounded\n");
        exit(0);
    }
    void pivot(int xA,int xB){
        swap(idA[xA], idB[xB]);
        static int next[N];
        int i,j,last = N-1;
        db tmp = -a[xB][xA]; a[xB][xA] = -1.0;
        for (j = 0;j <= n; j++)
            if(fabs(a[xB][j]) > EPS) a[xB][last = next[last] = j] /= tmp;
        next[last] = -1;

        for (i = 0; i <= m; i++)
            if(i != xB && fabs(tmp = a[i][xA]) > EPS)
            for (a[i][xA]=0.0, j = next[N - 1]; ~j; j = next[j]) a[i][j] += tmp * a[xB][j];
    }
    db calc(){
        int xA, xB;
        db Max, tmp;
        while(1){
            xA = n + 1, idA[xA] = n + m + 1;
            for (int i = 1; i <= n; i++)
                if(a[0][i] > EPS && idA[i] < idA[xA]) xA = i;

            if(xA == n + 1) return a[0][0];
//          cout<<a[0][0]<<endl;
            xB = m + 1, idB[xB] = n + m + 1, Max = -INF;
            for(int i = 1; i <= m; i++)
                if (a[i][xA] < -EPS && ((tmp = a[i][0] / a[i][xA]) > Max + EPS || tmp > Max - EPS && idB[i] < idB[xB])) Max = tmp,xB = i;

            if(xB == m + 1) put_out(1);

            pivot(xA, xB);
        }
        return a[0][0];
    } 
    db solve(){
        for (int i = 1; i <= n; i++) idA[i] = i;
        for (int i = 1; i <= m; i++) idB[i] = n + i;
        static db tmp[N];
        db Min=0.0;int l;
        for (int i = 1;i <= m;i++)
            if(a[i][0] < Min) Min = a[i][0], l = i;
        if(Min > -EPS) return calc();

        idA[++n] = 0;
        for (int i = 1;i <= m; i++) a[i][n] = 1.0;
        for (int i = 0;i <= n; i++) tmp[i] = a[0][i], a[0][i] = 0.0;
        a[0][n] = -1.0;

        pivot(n, l);

        if(calc() < -EPS) put_out(0);
        for (int i = 1; i <= m; i++)
            if(!idB[i]) {
                for (int j = 1; j <= n; j++)
                    if(fabs(a[0][j]) > EPS){
                        pivot(j, i);
                        break;
                }
                break;
        }

        int xA;
        for (xA = 1; xA <= n; xA++) if(!idA[xA]) break;
        for (int i=0;i<=m;i++)a[i][xA]=a[i][n];
        idA[xA]=idA[n], n--;

        for (int i = 0; i <= n; i++) a[0][i] = 0.0;
        for (int i = 1; i <= m; i++)
            if(idB[i] <= n) {
                for (int j = 0; j <= n; j++)
                    a[0][j] += a[i][j] * tmp[idB[i]];
            }

        for (int i = 1;i <= n; i++)
            if(idA[i] <= n) a[0][i] += tmp[idA[i]];
        return calc();
    }
    db ans[N];
    void findAns(){
        for (int i = 1; i <= n; i++) ans[i] = 0.0;
        for (int i = 1; i <= m; i++) 
            if(idB[i] <= n) ans[idB[i]] = a[i][0];
    }
    void work(){
        For(i,m) For(j,n) a[i][j]*=-1;
//      For(i,m){
//          For(j,n)cout<<a[i][j]<<' ';cout<<"<="<<a[i][0]<<endl;
//      }
//      int ta;
//      scanf("%d%d%d", &n, &m, &ta);
//      for (int i = 1; i <= n; i++) cin >> a[0][i];
//      for (int i = 1; i <= m; i++){
//          for (int j = 1; j <= n; j++){
//              cin >> a[i][j];
//              a[i][j]*= -1;
//          }
//          cin >> a[i][0];
//      }
        printf("%.10lf\n",-double(solve()));

//      if(ta){
//          findAns();
//          for (int i = 1; i <= n; i++)
//              printf("%.10lf ",abs(double(ans[i])));
//      }   
    }
}

/*input: 
n=变元数 m=方程数
Ax<=b x>=0 求max(Cx)?
b=A[i][0] ,C=A[0][i]

Ax<=b x>=0 求min(Cx)?
A转置,b,c交换  n,m交换
然后照做就行 
*/
#define MAXN (3000)
int g[MAXN];
int sum[MAXN],n,m,S;
int id[MAXN]={},vs[MAXN]={};
vi v[11];
db a2[MAXN][MAXN];
double calc(){
    LP::n=LP::m=0;
    Rep(i,S) if (sum[i]<=m) id[i]=++LP::n,vs[LP::n]=i;
    Rep(i,n){
        v[i].clear();
    }
    Rep(i,n) Rep(j,S) if(sum[j]<=m && ((j>>i)&1)) {
        v[i].pb(id[j]);
//      cout<<i<<'n'<<j<<endl;
    }
//  Rep(i,n){
//      for(int j:v[i])cout<<j<<' ';cout<<endl;
//      
//  }
    // n grops all euqal m
    // sum of all x =1
    // between 0~1
    // is_solution?
    Rep(i,n-1) { 
        int nowi=++LP::m;
        For(j,S) LP::a[nowi][j]=0;
        for(int j:v[i]) {
            LP::a[nowi][j] ++;
        }
        for(int j:v[i+1]) {
            LP::a[nowi][j] --;
        }
        LP::a[nowi][0]=0;

        nowi=++LP::m;
        For(j,S) LP::a[nowi][j]=-LP::a[nowi-1][j];
        LP::a[nowi][0]=0;
    }

    int i=++LP::m;
    For(j,LP::n) LP::a[i][j]=1;LP::a[i][0]=1;

    i=++LP::m;
    For(j,LP::n) LP::a[i][j]=-1;LP::a[i][0]=-1;

    Rep(i,S+1) LP::a[0][i]=0;
    for(int j:v[0]) {
        LP::a[0][j]++;
    }


    For(i,LP::m) For(j,LP::n) 
        a2[i][j]=LP::a[i][j];
    For(i,LP::m) For(j,LP::n)
         LP::a[j][i]=a2[i][j];
//  
    swap(LP::n,LP::m);
    For(i,max(LP::n,LP::m)){
        swap(LP::a[0][i],LP::a[i][0]);
    }
    LP::a[0][0]=0;
    For(i,LP::m) {
        For(j,LP::n) LP::a[i][j]*=-1;
    }
    For(i,LP::m) LP::a[i][0]*=-1;
    For(i,LP::n) LP::a[0][i]*=-1;

//  cout<<LP::n<<' '<<LP::m<<endl;

    LP::work(); 
}
int main()
{
    int T=read();
    For(kcase,T){
        n=read(),m=read();
        Rep(i,n) g[i]=read();
        S=1<<n;
        Rep(st,S) {
            sum[st]=0;
            Rep(j,n)if((st>>j)&1) {
                sum[st]+=g[j];
            }
        }
        printf("Case #%d: ",kcase);
        calc();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值