您的位置:首页 > 其它

Dual-SIM Phone

2015-08-26 20:29 330 查看

题意

nn个运营商,每个运营商可以发送短信给其他的一些运营商。彼得可以选两个运营商,通过两个运营商中花钱更少的一个发送短信给运营商。帮助彼得选择一对运营商,使得他能够发送短信给所有运营商,而且发送短信的最大费用最小。

n≤104n\le 10^4

运营商能发送短信的关系数k≤105k\le 10^5

TimeTime Limits:2000msLimits:2000ms

MemoryMemory Limits:64MLimits:64M

分析

这题其实就是暴力优化。

考虑二分答案。用bitsetbitset记录一个运营商ii在当前答案限制下能发给的运营商的集合SiS_i,并记录集合大小CiC_i。然后将CC数组从大到小排序,枚举两个运营商i,ji,j,显然,当n≤Ci+Cjn\le C_i + C_j 时i,ji,j才可能满足条件,所以我们做到一个Ci+Cj<nC_i +C_j < n时就可breakbreak。考虑到kk只是nn的十倍,这会是个非常高效的剪枝。

需要注意的是最好少使用bitsetbitset的函数。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>
using namespace std;

const int N = 1e4 + 10;
int g
,next[N * 10],to[N * 10],d[N * 10];
int n,m,c
,a
,tot;
bitset<N> s
,cur,full;

void add(int x,int y,int z) {
to[++ tot] = y;
next[tot] = g[x];
g[x] = tot;
d[tot] = z;
}

bool cmp(int a,int b) {
return c[a] > c[b];
}

bool check(int lim) {
for (int i = 1;i <= n;i ++) s[i].reset();
for (int u = 1;u <= n;u ++) {
c[u] = 0;
a[u] = u;
for (int i = g[u];i;i = next[i]) if (d[i] <= lim) {
int v = to[i];
if (s[u][v]) continue;
s[u][v] = 1;
c[u] ++;
}
}
sort(a + 1,a + 1 + n,cmp);
for (int i = 1;i < n;i ++) {
for (int j = i + 1;j <= n;j ++) if (c[a[i]] + c[a[j]] < n) break;
else {
cur = s[a[i]] | s[a[j]];
if (cur == full) return true;
}
}
return false;
}

int main() {
scanf("%d%d",&n,&m);
for (int i = 1;i <= m;i ++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
for (int i = 1;i <= n;i ++) full[i] = 1;
int ans = 1,r = 1e9;
while (ans < r) {
int mid = (ans + r) >> 1;
if (check(mid)) r = mid;
else ans = mid + 1;
}
if (check(ans)) printf("%d",ans);
else printf("No solution");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: