1. 程式人生 > 其它 >3205. 【HNOI模擬題】Dual-SIM Phone

3205. 【HNOI模擬題】Dual-SIM Phone

Description

彼得,一個學生,想要從簡訊業務中獲利。當然,他也想花最少的錢傳送資訊,並且儘快地傳送資訊。因此,他想買一個雙卡手機,對於兩個運營商的卡可以同時工作。現在,彼得可以傳送簡訊給某個電話號碼,通過兩個運營商中花錢更少的一個。

不幸的是,並非所有手機運營商可以通過他們傳送簡訊給其他運營商的電話號碼。幫助彼得選擇一對運營商,使得他能夠傳送簡訊給所有運營商的電話號碼,而且傳送簡訊的最大費用最小。

Solution

考慮直接暴力。

暴力列舉兩個點,然後暴力判斷這兩個點是否連向了所有點,求出最小的最大花費,更新答案。

時間複雜度看上去 \(O(MN^2)\),但是跑不滿。

另外可以加優化,判斷 兩個點有沒有沒有出度 的和 兩個點出度之和 是否大於 \(n\)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10005
#define M 100005
#define inf 2147483647
using namespace std;
struct node
{
	int x,y,z;
}a[M],c[M];
int n,m,x,y,z,ans,tot,st[N],out[N];
bool cmp(node x,node y)
{
	if (x.x<y.x) return true;
	if (x.x>y.x) return false;
	return x.y<y.y;	
}
void get(int x,int y)
{
	int i=st[x],j=st[y];
	tot=0;
	memset(c,0,sizeof(c));
	while (i<=m&&j<=m&&a[i].x==x&&a[j].x==y)
	{
		if (a[i].y<=a[j].y) c[++tot]=a[i++];
		else c[++tot]=a[j++];
	}
	while (i<=m&&a[i].x==x) c[++tot]=a[i++];
	while (j<=m&&a[j].x==y) c[++tot]=a[j++];
}
int solve(int x,int y)
{
	if (out[x]+out[y]<n) return inf;
	if (st[x]==-1||st[y]==-1) return inf;
	get(x,y);
	int res=0,num=0;
	for (int i=2;i<=tot+1;++i)
	{
		if (i==tot+1||c[i].y!=c[i-1].y)
		{
			res=max(res,c[i-1].z);
			++num;
		}
		else c[i].z=min(c[i].z,c[i-1].z);
		if (res>ans) break;
	}
	if (num<n) return inf;
	else return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;++i)
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),++out[a[i].x];
	sort(a+1,a+m+1,cmp);
	memset(st,-1,sizeof(st));
	st[a[1].x]=1;
	for (int i=2;i<=m;++i)
		if (a[i].x!=a[i-1].x) st[a[i].x]=i;
	ans=inf;
	for (int i=1;i<n;++i)
		for (int j=i+1;j<=n;++j)
			ans=min(ans,solve(i,j));
	if (ans==inf) printf("No solution\n");
	else printf("%d\n",ans);
	return 0;
}