直接对每种颜色建图,维护连通块个数。显然只要保证第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;
}