?? 最大公約數(shù)和問(wèn)題.cpp
字號(hào):
#include<iostream>
#include<math.h>
using namespace std;
/*
定理:
設(shè)M是一個(gè)帶權(quán)完全二分圖
G的一個(gè)完備匹配,給每個(gè)頂點(diǎn)一個(gè)
可行頂標(biāo)(第i個(gè)x頂點(diǎn)的可行標(biāo)用lx[i]表示
,第j個(gè)y頂點(diǎn)的可行標(biāo)用ly[j]表示),如果對(duì)所有的邊(i,j)
in G,都有l(wèi)x[i]+ly[j]>=w[i,j]成立(w[i,j]表示邊的權(quán)),
且對(duì)所有的邊(i,j) in M,都有l(wèi)x[i]+ly[j]=w[i,j]成立,
則M是圖G的一個(gè)最佳匹配。*/
const int MAX = 102;
int map[MAX][MAX];
int match[MAX],n,lx[MAX],ly[MAX];
bool x[MAX],y[MAX];
int gcd(int a, int b)
{
if(a < b)return gcd(b, a);
if(b == 0)return a;
return gcd(b, a%b);
}
bool dfs(int v)
{
int i,t;
x[v] = true;
for(i = 0; i < n; i++)
if(!y[i] && lx[v]+ly[i] == map[v][i]){
y[i] = true;
t = match[i];
match[i] = v;
if(t == -1 || dfs(t))
return true;
match[i] = t;
}
return false;
}
int main()
{
int i, j, test;
int num[102];
cin >> test;
while(test--)
{
cin >> n;
for(i = 0; i < n; i++)
cin >> num[i];
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
map[i][j] = -gcd(i+1, num[j]);
//初始化可行頂標(biāo)
for(i = 0; i < n; i++)
{
lx[i] = -0x1FFFFFFF;
ly[i] = 0;
for(j = 0; j < n; j++)
{
if(lx[i] < map[i][j])
lx[i] = map[i][j];
}
}
memset(match,-1,sizeof(match));
for(int k = 0; k < n; k++)
{
while(1)
{
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
if(dfs(k))//找到退出
break;
int dx = 0x7FFFFFFF;
for(i = 0; i < n; i++)
{
if(x[i])
for(j = 0; j < n; j++)
if(!y[j] && dx > (lx[i]+ly[j]-map[i][j]))
dx = lx[i]+ly[j]-map[i][j];
}
//修改可行頂標(biāo)
for(i = 0; i < n; i++)
{
if(x[i])
lx[i] -= dx;
if(y[i])
ly[i] += dx;
}
}
}
int sum = 0;
for(i = 0; i < n; i++)
{
sum += map[match[i]][i];
}
cout << -sum << endl;
}
return 0;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -