1.题目描述
- 共有 M 个客户节点和 N 个边缘节点。
- 在每个时刻,要决策如何把每个客户节点的带宽需求分配到边缘节点。
- 为了确保调度质量,每个客户节点的需求只能分配到满足 QoS 约束的边缘节点
上。即:当客户节点和边缘节点之间的 QoS 小于“QoS 上限”时,才会进行流量
分配。 - 在每个时刻,每个边缘节点接收的带宽需求总和不能超过其带宽上限。
- 合理分配所有时刻的客户节点带宽需求,使得最终的带宽总成本尽量小。
- 成本为某个边缘节点,统计它在每个时刻分配的带宽之和,这些值
在整个时间线上形成一个带宽序列,对其进行升序排序,以其 95%位置(向上
取整)的带宽值作为该节点的 95 百分位带宽。
7.总成本为求和所有边缘节点成本得到带宽总成本。
2.思路
将网络节点根据连接用户数量和带宽大小进行降序排序,让一部分节点每个时刻都尽量占用带宽,一部分节点只部署5%个时刻的带宽,这些节点的成本即为0。
如图,竖条为所有网络节点在所有时刻的带宽部署情况,横条为95%时刻位置,前一部分的网络节点带宽最大,连接用户数量最多,在每个时刻都尽量占用,而后面的节点只占用前5%。作为前一部分节点的数量称为阈值。
最终成绩为武长赛区43名,无缘复赛,只能拿到三等奖。
3.代码(Java)
注释还是比较清楚的,一些细节问题可以直接看。
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Properties;
public class Main {//文件名+路径+print
static int T,M,N,qos_constraint;
static String[][] demand,qos,site_bandwidth;
static ArrayList rear=new ArrayList();
public static void main(String[] args) {
output("");
demand=new String[8929][35];//T M [T-1][M-1] T<=8928,N<=135,M<=35 width=430080
site_bandwidth=new String[136][2];//N 2 [N-1][1]
qos=new String[136][35];//N M [N-1][M-1]
input();//T M N 101 11 101
int gate=T-(int) Math.ceil((T-1)*0.95)-1; //95位
Netnode[] netnodes=new Netnode[N];//1--N-1
for(int i=1;i<M;i++) {
for(int j=1;j<M;j++) {
if(demand[0][j].equals(qos[0][i])) {
for(int k=0;k<T;k++) {
String t=demand[k][i];
demand[k][i]=demand[k][j];
demand[k][j]=t;
}
break;
}
}
}
for(int i=1;i<N;i++) {
for(int j=1;j<N;j++) {
if(site_bandwidth[j][0].equals(qos[i][0])) {
netnodes[i]=new Netnode(Integer.parseInt(site_bandwidth[j][1]), T, M, qos[i], qos_constraint);//导入网络节点
break;
}
}
for(int j=1;j<i;j++) {
if(netnodes[j].t<netnodes[i].t) {//根据网络节点的连接用户数排序;'<'或'>'需要根据数据集实际情况进行调整
Netnode netnode=netnodes[i];
netnodes[i]=netnodes[j];
netnodes[j]=netnode;
}
}
}
for(int i=1;i<N;i++) {
for(int j=i+1;j<N;j++) {
if(netnodes[i].t==netnodes[j].t) {
if(netnodes[i].width<netnodes[j].width) {//连接用户数相同在根据总带宽排序;'<'或'>'需要根据数据集实际情况进行调整
Netnode netnode=netnodes[i];
netnodes[i]=netnodes[j];
netnodes[j]=netnode;
}
}else {
break;
}
}
}
int threshold=getthreshold(netnodes); //阈值,阈值前面的网络节点尽量塞满,后面的只塞5%
for(int i=threshold;i<N;i++) {
for(int j=i+1;j<N;j++) {
if(netnodes[i].t>netnodes[j].t) {//对阈值后面的节点根据网络节点的连接用户数排序;'<'或'>'需要根据数据集实际情况进行调整,记得和函数getthreshold里这部分同号
Netnode netnode=netnodes[i];
netnodes[i]=netnodes[j];
netnodes[j]=netnode;
}
}
}
for(int i=threshold;i<N;i++) {
for(int j=i+1;j<N;j++) {
if(netnodes[i].t==netnodes[j].t) {
if(netnodes[i].width>netnodes[j].width) {//连接用户数相同在根据总带宽排序;'<'或'>'需要根据数据集实际情况进行调整,记得和函数getthreshold里这部分同号
Netnode netnode=netnodes[i];
netnodes[i]=netnodes[j];
netnodes[j]=netnode;
}
}else {
break;
}
}
}
for(int i=1;i<T;i++) {
for(int j=1;j<M;j++) {
output(distribute(i, j, threshold, netnodes)+"\n");//进行模拟
}
for(int j=1;j<N;j++) {
netnodes[j].twidth=netnodes[j].width;//更新本轮带宽
}
for(int j=0;j<rear.size();j++) {
netnodes[(int) rear.get(j)].gate--;
}
rear.clear();
}
print(netnodes);//remove
}
public static int getthreshold(Netnode[] tnetnodes) {//测试最佳阈值
int threshold=0,cost=500000000;
Netnode[] netnodes=new Netnode[N];
for(int m=1;m<N;m++) { //测试最佳阈值
for(int i=1;i<N;i++) {
netnodes[i]=tnetnodes[i];
}
for(int i=m;i<N;i++) {
for(int j=i+1;j<N;j++) {
if(netnodes[i].t>netnodes[j].t) {//根据网络节点的连接用户数排序;'<'或'>'需要根据数据集实际情况进行调整
Netnode netnode=netnodes[i];
netnodes[i]=netnodes[j];
netnodes[j]=netnode;
}
}
}
for(int i=m;i<N;i++) {
for(int j=i+1;j<N;j++) {
if(netnodes[i].t==netnodes[j].t) {
if(netnodes[i].width>netnodes[j].width) {//对阈值后面的节点排序;'<'或'>'需要根据数据集实际情况进行调整
Netnode netnode=netnodes[i];
netnodes[i]=netnodes[j];
netnodes[j]=netnode;
}
}else {
break;
}
}
}
for(int i=1;i<T;i++) {
for(int j=1;j<M;j++) {
distribute(i, j, m, netnodes);
}
for(int j=1;j<N;j++) {
netnodes[j].twidth=netnodes[j].width;
}
for(int j=0;j<rear.size();j++) {
netnodes[(int) rear.get(j)].gate--;
}
rear.clear();
}
int sum=0;
for(int i=1;i<N;i++) {
Arrays.sort(netnodes[i].widtharray);
sum+=netnodes[i].widtharray[(int)Math.ceil((T-1)*0.95-1)];
}
if(cost>sum) {
cost=sum;
threshold=m;
}
for(int j=1;j<N;j++) {
for(int k=1;k<T;k++) {
netnodes[j].widtharray[k-1]=0;
netnodes[j].gate=T-(int) Math.ceil((T-1)*0.95)-1;
}
}
}
return threshold;
}
public static String distribute(int i,int j,int threshold,Netnode[] netnodes) {//分配算法
int need=Integer.parseInt(demand[i][j]);
String ts=demand[0][j]+":";
if(need==0) {
return ts;
}
for(int k=1;k<N;k++) {
if(netnodes[k].qos[j]<qos_constraint&&netnodes[k].twidth>0) {//判断用户能否接上该节点
if(k<threshold) {//N/4-(15-20) //判断该用户节点进去阈值前段还是阈值后段
if(need>netnodes[k].twidth) {
need-=netnodes[k].twidth;
netnodes[k].widtharray[i-1]=netnodes[k].width;
ts+="<"+netnodes[k].id+","+netnodes[k].twidth+">,";
netnodes[k].twidth=0;
}else if(need<=netnodes[k].twidth){
netnodes[k].twidth-=need;
netnodes[k].widtharray[i-1]+=need;
ts+="<"+netnodes[k].id+","+need+">";
need=0;
break;
}
}else {
if(netnodes[k].gate>0) { //判断阈值后端的节点是否还有位置(5%)
if(need>netnodes[k].twidth) {
need-=netnodes[k].twidth;
netnodes[k].widtharray[i-1]=netnodes[k].width;
ts+="<"+netnodes[k].id+","+netnodes[k].twidth+">,";
netnodes[k].twidth=0;
netnodes[k].gate--;
if(rear.contains(k)) {
rear.remove(rear.indexOf(k));
}
}else if(need<=netnodes[k].twidth){
netnodes[k].twidth-=need;
netnodes[k].widtharray[i-1]+=need;
ts+="<"+netnodes[k].id+","+need+">";
need=0;
if(!rear.contains(k)) {
rear.add(k);
}
//netnodes[k].gate--;
break;
}
}
}
}
}
if(need!=0) { //判断该用户节点的需求是否已经分配完
for(int k=threshold;k<N;k++) {
if(netnodes[k].qos[j]<qos_constraint&&netnodes[k].twidth>0) {
if(need>netnodes[k].twidth) {
need-=netnodes[k].twidth;
netnodes[k].widtharray[i-1]=netnodes[k].width;
ts+="<"+netnodes[k].id+","+netnodes[k].twidth+">,";
netnodes[k].twidth=0;
}else if(need<=netnodes[k].twidth){
netnodes[k].twidth-=need;
netnodes[k].widtharray[i-1]+=need;
ts+="<"+netnodes[k].id+","+need+">";
need=0;
break;
}
}
}
}
return ts;
}
public static void print(Netnode[] netnodes) {//打印结果
int sum1=0;
for(int i=1;i<N;i++) {
Arrays.sort(netnodes[i].widtharray);
//System.out.println(i+":"+Arrays.toString(netnodes[i].widtharray));
output(i+":"+Arrays.toString(netnodes[i].widtharray)+"\n\n");
sum1+=netnodes[i].widtharray[(int)Math.ceil((T-1)*0.95-1)];
}
System.out.println(sum1);
}
public static void input(){//输入
String line = "";
String tarray[];
int i=0,j=0;
try (BufferedReader br = new BufferedReader(new FileReader("D:\\华为软件挑战赛\\线下调试数据\\data1\\demand.csv"))) {//"/data/demand.csv"
while ((line = br.readLine()) != null) {
tarray = line.split(",");
for(j=0;j<tarray.length;j++) {
demand[i][j]=tarray[j];
}
i++;
}
T=i--;
M=j--;
} catch (IOException e) {
e.printStackTrace();
}
i=0;
try (BufferedReader br = new BufferedReader(new FileReader("D:\\华为软件挑战赛\\线下调试数据\\data1\\site_bandwidth.csv"))) {//"/data/site_bandwidth.csv"
while ((line = br.readLine()) != null) {
tarray = line.split(",");
for(j=0;j<tarray.length;j++) {
site_bandwidth[i][j]=tarray[j];
}
i++;
}
N=i--;
} catch (IOException e) {
e.printStackTrace();
}
i=0;
try (BufferedReader br = new BufferedReader(new FileReader("D:\\华为软件挑战赛\\线下调试数据\\data1\\qos.csv"))) {//"/data/qos.csv"
while ((line = br.readLine()) != null) {
tarray = line.split(",");
for(j=0;j<tarray.length;j++) {
qos[i][j]=tarray[j];
}
i++;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fin;
fin = new FileInputStream("D:\\华为软件挑战赛\\线下调试数据\\data1\\config.ini");//"/data/config.ini"
Properties props=new Properties();
props.load(fin);
qos_constraint=Integer.parseInt(props.getProperty("qos_constraint"));
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void output(String result) {//输出
String path="D:\\华为软件挑战赛\\线下调试数据\\data1\\output\\solution.txt";//"/output/solution.txt"
FileWriter fwriter = null;
try {
if(!result.equals("")) {
fwriter = new FileWriter(path, true);
fwriter.write(result);
}else {
fwriter = new FileWriter(path);
fwriter.write(result);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
fwriter.flush();
fwriter.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
class Netnode{ //网络节点类
public int width,twidth,t,gate;
public int[] qos,widtharray;//qos:1--m-1
String id;
public Netnode(int width,int T,int M,String[] d,int qc){
this.width=width;
twidth=width;
widtharray=new int[T-1];
gate=T-(int) Math.ceil((T-1)*0.95)-1;
qos=new int[M];
id=d[0];
for(int i=1;i<M;i++) {
qos[i]=Integer.parseInt(d[i]);
if(qos[i]<qc) {
t++;
}
}
}
}